Ruby on Rails - 嵌套属性:如何从子模型访问父模型

时间:2010-04-09 22:48:24

标签: ruby-on-rails nested-attributes

我有几个这样的模型

class Bill < ActiveRecord::Base
  has_many :bill_items
  belongs_to :store

  accepts_nested_attributes_for :bill_items
end

class BillItem <ActiveRecord::Base
  belongs_to :product
  belongs_to :bill

  validate :has_enough_stock

  def has_enough_stock
    stock_available = Inventory.product_is(self.product).store_is(self.bill.store).one.quantity
    errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity
  end
end

上述验证显然不起作用,因为当我从账单表单中的嵌套属性中读取bill_items时,属性bill_item.bill_id或bill_item.bill在保存之前不可用。

那我该怎么做呢?

5 个答案:

答案 0 :(得分:18)

这就是我最终解决的问题;通过在回调中设置父级

  has_many :bill_items, :before_add => :set_nest

private
  def set_nest(bill_item)
    bill_item.bill ||= self
  end

答案 1 :(得分:8)

在Rails 4中(未在早期版本上测试),您可以通过在inverse_ofhas_many上设置has_one选项来访问父模型:

class Bill < ActiveRecord::Base
  has_many :bill_items, inverse_of: :bill
  belongs_to :store

  accepts_nested_attributes_for :bill_items
end

文档:Bi-directional associations

答案 2 :(得分:1)

bill_item.bill应该可用,您可以尝试提升self.bill.inspect以查看它是否存在,但我认为问题出在其他地方。

答案 3 :(得分:1)

我通过在回调中设置父级来“修复”它:

class Bill < ActiveRecord::Base
  has_many :bill_items, :dependent => :destroy, :before_add => :set_nest
  belongs_to :store

  accepts_nested_attributes_for :bill_items

  def set_nest(item)
    item.bill ||= self
  end
end

class BillItem <ActiveRecord::Base
  belongs_to :product
  belongs_to :bill

  validate :has_enough_stock

  def has_enough_stock
        stock_available = Inventory.product_is(self.product).store_is(self.bill.store).one.quantity
    errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity
  end
end

set_nest方法成功了。希望它标准化为accepts_nested_attributes_for。

答案 4 :(得分:0)

是的,这种问题可能很烦人。您可以尝试将虚拟属性添加到Bill Item模型中,如下所示:

class BillItem <ActiveRecord::Base
  belongs_to :product
  belongs_to :bill

  attr_accessible :store_id

  validate :has_enough_stock

  def has_enough_stock
   stock_available = Inventory.product_is(self.product).store_is(load_bill_store).one.quantity
   errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity
  end

  private

  def load_bill_store
    Store.find_by_id(self.store_id)
  end
end

然后在您的视图中,您可以添加如下隐藏字段:

<%= bill_item.hidden_field :store_id, :value => store_id %>

这尚未经过测试,但可能有效。你可能不会觉得在html中使用store_id是可取的,但它可能不是一个问题。如果这有帮助,请告诉我。