#ruby-on-rails #ruby-on-rails-3 #validation #activerecord #has-many-through
#ruby-on-rails #ruby-on-rails-3 #проверка #activerecord #имеет много сквозных
Вопрос:
У меня есть has_many через ассоциацию с атрибутом и некоторые проверки в «модели объединения». Когда я пытаюсь сделать что-то подобное @user.projects << @project
, и ассоциация уже создана (таким образом, проверка уникальности завершается неудачей), вместо ошибки, добавляемой к ошибкам проверки, возникает исключение.
class User
has_many :project_users
has_many :projects, :through => :project_users
class Project
has_many :project_users
has_many :users, :through => :project_users
class ProjectUser
belongs_to :user
belongs_to :project
# ...
if @user.projects << @project
redirect_to 'somewhere'
else
render :new
end
Как я могу создать ассоциацию, как с <<
методом, но вызывая save
вместо save!
, чтобы я мог показывать ошибки проверки в своей форме вместо того, чтобы использовать a rescue
, чтобы перехватить это и обработать соответствующим образом?
Ответ №1:
Я не думаю, что вы можете. Из API:
коллекция<<(object, …) Добавляет один или несколько объектов в коллекцию, устанавливая их внешние ключи в первичный ключ коллекции. Обратите внимание, что эта операция мгновенно запускает update sql, не дожидаясь вызова save или update для родительского объекта.
и
Если при замене коллекции (через association= ) происходит сбой сохранения, возникает исключение ActiveRecord::RecordNotSaved и назначение отменяется.
Обходной путь может выглядеть следующим образом:
if @user.projects.exists? @project
@user.errors.add(:project, "is already assigned to this user") # or something to that effect
render :new
else
@user.projects << @projects
redirect_to 'somewhere'
end
Это позволило бы вам обнаружить сбой там, где ассоциация уже существует. Конечно, если другие проверки ассоциации могут быть неудачными, вам все равно нужно перехватить исключение, так что это может быть не очень полезно.
Комментарии:
1. Хм. Я видел это в документах API, но на самом деле это не относится к тому, что он делает со связанной моделью. Используя
:through
, он фактически запускает проверки и обратные вызовы, как обычно, в «модели объединения». Бит о возникновенииActiveRecord::RecordNotSaved
ошибки не имеет значения, потому что он ссылается на замену / назначение коллекцииassociation =
.
Ответ №2:
Может быть, вы могли бы попробовать добавить проверку в свою модель проекта, например:
проверяет: идентификатор пользователя, : уникальность => {: область действия => : идентификатор пользователя}, :on =>:создать
Не уверен, поможет ли это избежать сохранения! метод..
Комментарии:
1.
project
Модель не имеет abelongs_to :user
, поэтому нетuser_id
атрибута для проверки.
Ответ №3:
Попробуйте объявить ассоциации как
has_many :projects, :through => :project_users, :uniq => true
Извлеките раздел 4.3.2.21 в http://guides.rubyonrails.org/association_basics.html .
Комментарии:
1. Хорошая попытка, но на самом деле это вообще не обеспечивает уникальность. Цитата из раздела руководства, на который ссылается ссылка: «В приведенном выше случае все еще есть два чтения. Однако person.posts показывает только одно сообщение, потому что коллекция загружает только уникальные записи. » В любом случае попробовал, и на самом деле он даже загружает несколько идентичных записей, так что никакого эффекта вообще.