【问题标题】:Ruby on Rails - nested attributes: How do I access the parent model from child modelRuby on Rails - 嵌套属性:如何从子模型访问父模型
【发布时间】:2010-04-09 22:48:23
【问题描述】:

我有几个这样的模型

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 在保存之前不可用。

那么我该怎么做这样的事情呢?

【问题讨论】:

  • 我通过向关联添加回调来解决这个问题,:before_add => :set_nest

标签: ruby-on-rails nested-attributes


【解决方案1】:

这就是我最终解决的方法;通过在回调上设置父级

  has_many :bill_items, :before_add => :set_nest

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

【讨论】:

  • 是的!最近一直困扰着我。我希望它是自动的,如果针对关联代理(如关联扩展)而不是关联所有者运行回调函数,则可以编写更通用的版本。
【解决方案2】:

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

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

  accepts_nested_attributes_for :bill_items
end

文档:Bi-directional associations

【讨论】:

  • 这是 rails 4 的真实答案
【解决方案3】:

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

【讨论】:

  • 即使它不可用,OP 也可以添加一个 before_validation 回调来设置它。 BillItems 不需要知道自己的 ID 或父 Bill 的 ID 即可验证。
【解决方案4】:

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

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。

【讨论】:

    【解决方案5】:

    是的,这种问题可能很烦人。您可以尝试向 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,但这可能不是问题。让我知道这是否有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-15
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多