简体   繁体   English

如何确保关联的属性正确才能验证关联?

[英]How do I make sure an association's attribute is correct to validate the association?

I've got a simple user: **Edited a bit for clarity, and on Sam's suggestion 我有一个简单的用户:**为了清晰起见,并根据Sam的建议进行了一些编辑

class User < ActiveRecord::Base
  # <snip other attribs>
  has_many :handles
  has_one :active_handle, :class_name => "Handle"

  validates_each :active_handle, :allow_nil => true  do |record, attr, value|
    record.errors.add attr, "is not owned by the correct user" unless record.handles.include?(value)
  end
end

And a handle model: 和句柄模型:

class Handle < ActiveRecord::Base
  belongs_to :user
  attr_accessible :user_id
  validates :user_id,
        :presence => true,
        :numericality => true

  attr_accessible :name
  validates :name,
        #etc...
end

Now I'd like to check, when setting the User.active_handle association, that the handle is owned by the correct Handle.user_id. 现在,我想在设置User.active_handle关联时检查该句柄是否由正确的Handle.user_id拥有。 I've tried to do this in a custom validation, and also in a validate method on the User model. 我尝试在自定义验证中以及在User模型上的validate方法中执行此操作。 Both ways, it does the exact opposite of what I want, it sets the user_id of handle to the User doing the checking. 两种方式都与我想要的完全相反,它将句柄的user_id设置为进行检查的用户。

I'm at the end of my rope, clearly I don't understand something, and google isn't getting me anywhere I haven't already been. 我已经走到尽头了,很明显,我听不懂什么,而google并没有把我带到从未有过的地方。

ETA: I have also tried to manipulate the has_one association with conditions, that seems to fail too... ETA:我也尝试过操纵has_one与条件的关联,这似乎也失败了...

has_one :active_handle,
        :class_name => "Handle",
        :conditions => ['user_id =?', '#{self.id}']

If your doing it from the user model then you need to add the validation to the user model instead of the handle model because the user is what's getting updated. 如果您是从用户模型执行此操作,则需要将验证添加到用户模型而不是句柄模型,因为要更新的是用户。

This is how I would validate that the user actually belongs to the handle before it can be made active. 这就是我可以在使用户变为活动状态之前验证用户实际上属于该句柄的方式。

class Handle < ActiveRecord::Base
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :handles
  validates :handle_can_be_active?

  def handle_can_be_active?
      if self.handles.include?(self.active_handle)
          #no problem
      else
          errors.add_to_base('Must belong to the handle before it can be active!')
      end
  end
end

I'd take a different approach to this problem; 对于这个问题,我会采取不同的方法。 the double link is messy, and hard to maintain, as you've discovered. 正如您所发现的,双链接是混乱的,并且难以维护。 Instead, I'd put an active flag in the handle model, and order the :active_handle association on that flag: 相反,我会在句柄模型中放置一个活动标志,并在该标志上排序:active_handle关联:

class User < ActiveRecord::Base
    has_many :handles
    has_one  :active_handle, :class_name => 'Handle', :order => 'handles.active DESC'
end

Now there's only one link, and it's the same link that's already in place to establish the plain has_many :handles association (namely, the user_id attribute in the Handle model). 现在只有一个链接,并且该链接已经用于建立简单的has_many :handles关联(即Handle模型中的user_id属性)。 Finding the active handle in now just a matter of finding the User's first Handle with the active flag set. 现在,要找到活动手柄,只需查找设置了活动标志的用户的第一个手柄即可。 And I'd use :order rather that :conditions , as that'll give you a nice fallback: If no Handle for that user has the active flag set, Rails'll pick one to use as a default. 我将使用:order而不是:conditions ,因为这将为您提供一个不错的后备:如果没有为该用户的Handle设置了活动标志,Rails会选择一个作为默认标志。

And then, in your handle model, you can have a fairly simple activate function: 然后,在句柄模型中,您可以具有一个相当简单的激活函数:

class Handle < ActiveRecord::Base
    # ...stuff...

    def activate!
        # Pseudocode - sorry!
        sql('UPDATE handles SET active = 0 WHERE user_id = ?', self.user_id)
        self.active = true
        self.save!
    end
end

Or, if you wanted to be able to call something like user.handles.activate(hdl) , you could put something similar as an association extension. 或者,如果您希望能够调用诸如user.handles.activate(hdl)东西,则可以放置类似于关联扩展名的东西。 Or user.active_handle = hdl . user.active_handle = hdl Or... 要么...

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM