Ruby on Rails - вложенные атрибуты: как получить доступ к родительской модели из дочерней модели - PullRequest
20 голосов
/ 10 апреля 2010

У меня есть пара таких моделей, как

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, атрибуты bill_item.bill_id или bill_item.bill недоступны перед сохранением.

Итак, как мне поступить так?

Ответы [ 5 ]

18 голосов
/ 19 февраля 2011

Вот как я решил это в конце концов; установив родителя на обратный вызов

  has_many :bill_items, :before_add => :set_nest

private
  def set_nest(bill_item)
    bill_item.bill ||= self
  end
8 голосов
/ 23 апреля 2015

В Rails 4 (не тестировался в более ранних версиях) вы можете получить доступ к родительской модели, установив параметр inverse_of на has_many или has_one:

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

  accepts_nested_attributes_for :bill_items
end

Документация: Двунаправленные ассоциации

1 голос
/ 25 апреля 2010

Bill_item.bill должен быть доступен, вы можете попытаться сделать рейз self.bill.inspect, чтобы увидеть, есть он или нет, но я думаю, что проблема в другом.

1 голос
/ 28 января 2011

Я "исправил" это, установив родителя в обратном вызове:

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 добился цели. Хотелось бы, чтобы это было стандартным с acceptpts_nested_attributes_for.

0 голосов
/ 10 апреля 2010

Да, такая проблема может раздражать.Вы можете попробовать добавить виртуальный атрибут в модель Билла следующим образом:

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 %>

Это неЭто был тест, но это может сработать.Возможно, вы не захотите указывать store_id в html, но это может не беспокоить.Позвольте мне знать, если это помогает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...