2014-12-08 7 views
1

У меня есть Company, User и Department модель. Существует несколько разных компаний, каждая из которых - has_many отделов.Rails Валидация по атрибуту has_many

A User может принадлежать нескольким Departments через таблицу UserDepartments.

В моей форме для User, я использую:

<%= f.collection_check_boxes :department_ids, @user.company.departments.all, :id, :name %> 

Что является лучшей практикой для проверки того, что злоумышленник не использовать Curl и т.д., чтобы опубликовать department_id, что не принадлежит компании пользователя?

В настоящее время я использую следующую таблицу соединений, но мне интересно, есть ли более приемлемая практика?

class UserDepartment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :department 

    validate :check_company_matches 

    private 
    def check_company_matches 
     unless user.company_id == department.company_id 
     errors.add(:user, "This department does not match the user's company.") 
     end 
    end 
end 

В отдельной записке, если пользователь делает отправить вредоносный идентификатор, рельсы показывает страницу скорее исключения, чем обычная страницу формы визуализации с объектом ошибки; почему это?

Еще одним незначительным моментом неплатежеспособности является то, что при отправке пользовательской формы с указанием 5 различных отделов эта проверка будет создавать 5 SQL-запросов. Предположительно это можно сделать с помощью одного запроса, если сама модель User провела проверку. Естественно, целостность данных - моя главная проблема.

Спасибо.

+0

Возможно, не стоит добавлять валидацию в модель таблицы соединений. Можете ли вы опубликовать код модели отдела и модели пользователя? – kasperite

+0

@kasperite это просто пример: Департамент просто 'принадлежит_то: компания' и Пользователь' принадлежит_от: компании' и 'has_many: user_departments',' has_many: отделы, через:: user_departments'. –

ответ

0

То, что остановит вредоносного пользователя от зависания на вашем сервере, это csrf_token, поэтому Rails заботится об этом. Вероятно, это ошибка, которую вы видите.

Я бы сохранил бизнес-логику, как подтверждение на Веществе, которое оно проверяет. Таблица соединений - это не сама Вещь; на самом деле у него нет Вещей.

Итак, переместив проверку на пользователя, вы держите логику в одном месте и избегаете дополнительного sql.

def ensure_departments_in_company 
    company_department_ids = company.departments.pluck(:id) 
    unless deparment_ids.map { |id| id.in?(company_department_ids) }.all? 
    errors.add(:user, "This department does not match the user's company.") 
    end 
end 
+0

Спасибо, пример скручивания был действительно неправильным. Однако, если я перехожу к «проверке элемента», например, Safari в одном из флажков и измените значение на другой номер, то без этой проверки Rails установит отдел пользователя на тот, который не может принадлежать компании пользователя. Я проверил ваш код, и он работает, спасибо. Я добавил ошибку вместо символа ': department'. –

Смежные вопросы