Избегайте «сохранить!» На много через ассоциацию - PullRequest
3 голосов
/ 02 октября 2011

У меня есть 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!, чтобы я мог показать ошибки проверки в моей форме вместо использования rescue, чтобы поймать это и обращаться с этим соответствующим образом?

Ответы [ 3 ]

0 голосов
/ 02 октября 2011

Может быть, вы могли бы попытаться добавить проверку в модель вашего проекта, например:

validates: user_id,: uniqueness => {: scope =>: user_id},: on =>: create

Не уверен, поможет ли это избежать сохранения!способ ..

0 голосов
/ 03 октября 2011

Попробуйте объявить ассоциации как

has_many :projects, :through => :project_users, :uniq => true

Извлечь раздел 4.3.2.21 в http://guides.rubyonrails.org/association_basics.html.

0 голосов
/ 02 октября 2011

Не думаю, что ты можешь. Из API :

collection << (object,…) Добавляет один или несколько объектов в коллекцию с помощью установка их внешних ключей на первичный ключ коллекции. Обратите внимание, что эта операция мгновенно запускает обновление sql, не дожидаясь сохранения или обновить вызов родительского объекта. </p>

и

Если сохранение не удастся при замене коллекции (через ассоциацию =), 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

Это позволит вам уловить ошибку, когда ассоциация уже существует. Конечно, если другие проверки для ассоциации могут быть неудачными, вам все равно нужно перехватить исключение, поэтому оно может быть не очень полезным.

...