Ответ 1
Вот как я решил это в конце концов; путем установки родителя при обратном вызове
has_many :bill_items, :before_add => :set_nest
private
def set_nest(bill_item)
bill_item.bill ||= self
end
У меня есть пара таких моделей
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 недоступны до сохранения.
Итак, как я могу сделать что-то подобное?
Вот как я решил это в конце концов; путем установки родителя при обратном вызове
has_many :bill_items, :before_add => :set_nest
private
def set_nest(bill_item)
bill_item.bill ||= self
end
В 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
Документация: Двунаправленные ассоциации
Bill_item.bill должен быть доступен, вы можете попробовать сделать raise self.bill.inspect, чтобы увидеть, есть он там или нет, но я думаю, что проблема в другом месте.
Я "исправил" его, установив родительский элемент в обратном вызове:
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.
Да, такая проблема может быть раздражающей. Вы можете попробовать добавить виртуальный атрибут в свою модель Билла 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 %>
Это не было тестом, но это может сработать. Возможно, вам не кажется желательным иметь store_id в html, но это может и не быть проблемой. Позвольте мне знать, если это помогает.