4

У меня есть модель пользователя с отношением HABTM к группам. Я не хочу, чтобы пользователь мог быть в более чем 5 группах, поэтому хотел бы подтвердить длину отношений HABTM.Проверка длины ассоциации habtm без сохранения

На странице редактирования пользователя у меня есть список флажков, где пользователь может выбрать группы, в которых они хотят находиться (я использую formtastic для формы).

В моем контроллере пользователей я звоню:

@user.update_attributes(params[:user]) 

, которая вызывает рельсы автоматически обновлять ассоциации.

В моей модели пользователя у меня есть следующие:

def validate 
    if self.groups.length > 5 
     self.errors.add(:groups, "cannot have more than 5 groups") 
    end 
end 

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

Каков наилучший способ решить эту проблему?

Я думаю, что, возможно, валидация должна быть на групповой модели вместо модели пользователя, будет ли это работать? В идеале я хотел бы обновить связанные группы без сохранения записи, выполнить проверку и THEN сохранить запись.

ответ

11

У вас было две проблемы здесь:

  1. Вы переопределение валидаций
  2. Порядок операций в экономии вызывает проблемы.

Вы переписываете метод проверки, что плохо, потому что встроенное поведение запрещает записи с ошибками проверки, которые должны быть сохранены в базе данных. Для добавления пользовательских валидаций вы хотите сделать это:

validate :maximum_group_length 

def maximum_group_length 
    if self.groups.length > 5 
     self.errors.add(:groups, "cannot have more than 5 groups") 
    end 
end 

Однако характер HABTM отношений требует, чтобы сделать это как after_save обратного вызова. Просто из-за того, что все сделано. user.groups основан на неявной таблице соединений и там для не обновляется до тех пор, пока таблица соединений не будет обновлена.

Если вы пытаетесь проверить как часть обратного вызова (before_save, after_creation и т. Д.), То добавление ошибки к объекту не приведет к откату. Обратные вызовы вызовут только откат, если они вернут false. Вопрос будет рассмотрен после сохранения.

after_save :validate_maximum_group_length 

def validate_maximum_group_length 
    if self.groups.length > 5 
     self.errors.add(:groups, "cannot have more than 5 groups") 
     return false 
    end 
end 

Другим решением является использование явной модели объединения. И has_many: через отношения. Таблица объединенной модели обновляется в инструкции обновления. Где, когда отношения has_many: through и HABTM обновляют отношения после сохранения.

class User < ActiveRecord::Base 
    has_many :user_groups 
    has_many :groups, :through => user_groups, allow_destroy 

    validate :max_group_length 
    errors.add(:groups, "cannot have more than 5 groups") if self.user_groups.length > 5 
    end 

end 

class UserGroup < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :group 
end 

class Group < ActiveRecord::Base 
    has_and_belongs_to_many :users 
end 

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

Однако вам нужно будет изменить свою форму, чтобы обновить форму, чтобы поставить group_id в Params хэш, как params[:user][:user_group_attributes][0][:group_id][3]

+0

Это не решает, он все еще сохраняющиеся изменения. – jonnii

+0

Похоже, я неправильно определил вашу проблему, я думал, что вы проверяете как обратный вызов. Проблема заключалась в том, что вы переопределяли проверку. – EmFi

+0

Я переместил проверку в пользовательскую процедуру проверки, как предполагалось, но это все еще не решает проблему. – jonnii

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