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已经更新数据库,以反映更改相关联基团。这样每次用户点击保存按钮时,他们的组关联都会被保存,即使记录无效。

解决此问题的最佳方法是什么?

我想可能验证需要在组模型而不是用户模型,这将工作?理想情况下,我想更新相关组而不保存记录,进行验证,然后保存记录。

回答

11

您在这里度过了两个问题:

  1. 你覆盖了验证
  2. 储蓄的操作顺序导致的问题。

您正在覆盖validate方法,这是一件坏事,因为内置的行为将拒绝具有验证错误的记录保存到数据库。要添加自定义验证要做到这一点:

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隐式使用连接表,因此不需要在组侧进行更改。

然而,你将需要修改表单更新形式params哈希表提供GROUP_ID作为params[:user][:user_group_attributes][0][:group_id][3]

+0

这并不能解决问题,它仍然坚持的变化。 – jonnii 2009-10-19 21:32:07

+0

看起来我误诊了你的问题,我以为你正在验证为回调。问题是你正在重新定义验证。 – EmFi 2009-10-19 21:47:27

+0

我已经按照建议将验证移入了自定义验证例程,但这仍然无法解决问题。 – jonnii 2009-10-19 21:48:51

相关问题