2011-09-01 18 views
7

我试图做到这一点默默跳过添加before_add关联回调,而不是引发异常?

has_many :roles, :before_add => :enforce_unique 

def enforce_unique(assoc) 
    false if exists? assoc 
end 

从文档:“如果一个before_add回调抛出一个异常,对象不会被添加到集合”。在使用上述虚假不阻止补充,所以我不得不这样做:

def enforce_unique(assoc) 
    raise if exists? assoc 
end 

这样一来,这是真的,它不会增加,但同时也提出了一个必须处理的异常。这里对我不太有用。我更喜欢这种行为更像普通的AR回调before_save,其中返回FALSE也阻止保存(或添加),但不会引发异常。

在上面的例子中,我宁愿这样做只是不会默默地添加关联。有没有办法做到这一点?我错过了什么?或者在这里提出一个例外唯一的选择?

回答

1

如果该关联不是多态的,你可以这样做:

validates_uniqueness_of :name_of_model 

角色里面,其中name_of_model我们你与

1

这个问题是有点老了关联,但我碰到最近同样的问题。这里是我如何解决它:

def enforce_unique |obj, x| 
    v = obj.roles 
    if i = v.index(x) 
    v.slice! i 
    end 
end 
2

的方式来解决这个问题,我认为是用throwcatch,这在红宝石都是为了流量控制。提出例外并不适合,因为这不是一个特殊的情况。

我落得这样做:

catch(:duplicate) do 
    association.create({}) 
end 

然后在before_add回调,我所做的:

if(Class.where({}).first) 
    throw :duplicate 
end 

更多关于掷/赶上这里:

http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue-im-so-confused/

0

由于这个问题是关于保存而不是阻止它被包含列表中的d暂时(例如,通过控制器没有兴趣控制其型号),你可以尝试重写保存在相关模型,如果角色存在只是没有保存:

class Role < ActiveRecord::Base 
    belongs_to :user, inverse_of: :roles 

    def save 
    super unless self.new_record? && user.has_existing_role?(self) 
    end 
end 

旁注:我不当与Active Record模式一起使用时,不要购买skinny控制器参数,因为业务逻辑必须放在某处。对于像Active Record这样的业务领域不良模式(不是专指Ruby AR gem),它实际上需要在上面存在一层(即在控制器层中),您可以使用服务对象或装饰器模式作为实现此目的的一种手段。

另一种方法是覆盖关联的更新方法,如关联<<,并在与现有角色匹配时自动放弃角色。重写关联方法的详细信息在ActiveRecord Association Class Methods Documentation