2010-11-09 49 views
3

我有两个ActiveRecord类。这些类的简化图:防止has_many集合中最后一条记录被删除的最佳方法是什么?

class Account < ActiveRecord::Base 
    has_many :user_account_roles 
end 

class UserAccountRole < ActiveRecord::Base 
    belongs_to :account 

    # Has a boolean attribute called 'administrator'. 
end 

我正在挣扎的是,我希望能够在两个验证规则适用于本: *确保最后UserAccountRole不能删除。 *确保无法删除管理员的最后一个UserAccountRole。

我真的很难理解实现这种结构验证的最佳方式。我尝试添加一个before_remove回调到关联,但我不喜欢这必须抛出一个错误,这将需要被控制器捕获。我宁愿把它当作“只是另一种验证”。

class Account < ActiveRecord::Base 
    has_many :user_account_roles, :before_remove => check_remove_role_ok 

    def check_remove_relationship_ok(relationship) 
    if self.user_account_relationships.size == 1 
     errors[:base] << "Cannot remove the last user from this account." 
     raise RuntimeError, "Cannot remove the last user from this account." 
    end 
    end 

end 

我不认为什么差别,但我还使用accepts_nested_attributes_for。

回答

2

为什么不在帐户上使用简单验证?

class Account < ActiveRecord::Base 
    has_many :user_account_roles 

    validate :at_least_one_user_account_role 
    validate :at_least_one_administrator_role 

    private 
    def at_least_one_user_account_role 
    if user_account_roles.size < 1 
     errors.add_to_base('At least one role must be assigned.') 
    end 
    end 

    def at_least_one_administrator_role 
    if user_account_roles.none?(&:administrator?) 
     errors.add_to_base('At least one administrator role must be assigned.') 
    end 
    end 
end 

这样,没有什么需要提高,这个记录不会被保存,除非有至少一个角色,和至少一个管理员角色。因此,当您错误地重新编辑编辑表单时,将显示此消息。

+0

好吧,不能相信这就是这么简单!认为Rails不够智能,无法自动管理它。我确实必须将验证设置为只在更新而不是创建时触发,否则实际上首先创建关系变得棘手。除此之外,似乎工作正常:)谢谢! – 2010-11-11 07:10:28

+0

P.S.必须按照如下方式调整'at_least_one_user_account_role',以使验证规则在保存记录之前在验证中发现:if user_account_relationships.size <1 || user_account_relationships.all? {| r | r.marked_for_destruction?} – 2010-11-11 21:57:46

0

您可以将验证放在UserAccountRole上。如果它是唯一与帐户关联的UserAccountRole,则不能删除它。

更简单的解决方案可能是质疑您的设计的基本假设。为什么UserAccountRole是AR支持的模型?为什么不把它变成一个普通的红宝石课程?最终用户是否会动态定义角色?如果没有,那么你可以通过将其定义为一个常规的ruby类来大大简化你的困境。

相关问题