Ruby on Rails在保存之前通过关联对象具有很多功能

时间:2012-03-15 21:30:14

标签: ruby-on-rails ruby has-many-through

在Ruby on Rails项目上我试图在将所有内容保存到数据库之前访问ActiveRecord上的关联对象。

class Purchase < ActiveRecord::Base

  has_many :purchase_items, dependent: :destroy
  has_many :items, through: :purchase_items

  validate :item_validation

  def item_ids=(ids)
    ids.each do |item_id|
      purchase_items.build(item_id: item_id)
    end
  end

  private

  def item_validation
    items.each do |item|
      ## Lookup something with the item
      if item.check_something
        errors.add :base, "Error message"
      end
    end
  end

end

如果我像这样构建我的对象: purchase = Purchase.new(item_ids: [1, 2, 3])并尝试保存item_validation方法尚未填充项目集合,因此即使已设置项目设置,也无法调用check_something任何一种方法。

是否可以在我的购买模型和关联模型持久化之前访问项目集合,以便我可以针对它们运行验证?

如果我将item_validation方法更改为:

def item_validation
  purchase_items.each do |purchase_item|
    item = purchase_item.item
    ## Lookup something with the item
    if item.something
       errors.add :base, "Error message"
    end
  end
end

它似乎按照我想要的方式工作,但是我发现很难相信在我购买之前没有办法直接访问带有rails的items集合,并且相关记录被保存到数据库中。

5 个答案:

答案 0 :(得分:1)

尝试在has_many和belongs_to定义中添加参数inverse_of :. inverse_of参数是另一个模型上关系的名称,例如:

class Post < ActiveRecord::Base
  has_many :comments, inverse_of: :post
end

class Comment < ActiveRecord::Base
  belongs_to :post, inverse_of: :comments
end

不要忘记将其添加到其他类上,例如PurchaseItem和Item

希望有所帮助

答案 1 :(得分:1)

删除您自己的item_ids=方法 - rails会为您生成一个方法(请参阅collection_singular_ids=ids)。这可能已经解决了你的问题。

class Purchase < ActiveRecord::Base

  has_many :purchase_items, dependent: :destroy
  has_many :items, through: :purchase_items

  validate :item_validation

  private

  def item_validation
    items.each do |item|
      ## Lookup something with the item
      if item.check_something
        errors.add :base, "Error message"
      end
    end
  end

end

我想到的第二件事就是查看你的代码:将验证移到Item类。所以:

class Purchase < ActiveRecord::Base
  has_many :purchase_items, dependent: :destroy
  has_many :items, through: :purchase_items
end

class Item < ActiveRecord::Base
  has_many :purchase_items
  has_many :purchases, through: :purchase_items

  validate :item_validation

  private

  def item_validation
      if check_something
        errors.add :base, "Error message"
      end
  end
end

如果其中一个Purchase无效,您的Item记录也将无效。

答案 2 :(得分:0)

您是否有文档表明purchase = Purchase.new(item_ids: [1, 2, 3])符合您的期望?

对我而言,您只是将非数据库属性'item_ids'设置为数组(即不创建关联)。

您的购买模型甚至不应该直接设置任何外键列。相反,purchase_items表中的条目有purchase_iditem_id。要在您的购买和三个项目之间创建链接,您需要在加入者表格中创建三个条目。

如果你这样做会发生什么?:

purchase = Purchase.new
purchase.items = Item.find([1,2,3]) 

答案 3 :(得分:0)

您可以使用model.associations = [association_objects]Association Callback http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Association+callbacks

答案 4 :(得分:0)

我认为您无法访问它们,因为id Purchase在保存记录之前无法使用purchase_items。但正如您所提到的,您可以访问第一级关联where,因此您可以提取所有ID并将其Item传递给items = Item.where(purchase_item_id: purchase_items.map(&:id))

.clone()