2010-04-09 7 views
20

Tôi có một vài mô hình như vậyRuby on Rails - thuộc tính lồng nhau: Làm thế nào để truy cập vào các mô hình mẹ từ mô hình con

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 

Việc xác nhận trên như vậy rõ ràng không hoạt động bởi vì khi tôi đang đọc bill_items từ các thuộc tính lồng nhau bên trong biểu mẫu hóa đơn, các thuộc tính bill_item.bill_id hoặc bill_item.bill không có sẵn trước khi được lưu.

Vậy làm cách nào để tôi thực hiện những việc như vậy?

+0

Tôi đã giải quyết vấn đề này bằng cách thêm một cuộc gọi lại cho liên kết,: before_add =>: set_nest – TMaYaD

Trả lời

18

Đây là cách tôi giải quyết nó cuối cùng; bằng cách thiết lập mẹ trên callback

has_many :bill_items, :before_add => :set_nest 

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

Vâng! Nó đã được bugging tôi gần đây. Tôi muốn nó là tự động, người ta có thể viết một phiên bản chung chung hơn nếu các chức năng gọi lại được chạy với proxy kết hợp (như phần mở rộng liên kết) thay vì chủ sở hữu liên kết. – ilpoldo

0

Vâng, loại sự cố này có thể gây phiền toái. Bạn có thể thử thêm một thuộc tính ảo để Giỏ Hàng Bill của bạn như thế này:

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 

Và sau đó theo quan điểm của bạn, bạn có thể thêm một lĩnh vực tiềm ẩn như thế này:

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

này chưa được thử nghiệm nhưng có thể đấy. Bạn có thể không tìm thấy nó mong muốn để có store_id trong html nhưng nó có thể không phải là một mối quan tâm. Hãy cho tôi biết nếu điều này sẽ giúp.

1

Bill_item.bill sẽ khả dụng, bạn có thể thử tự nâng cao.bill.inspect để xem có ở đó hay không, nhưng tôi nghĩ sự cố là ở nơi khác.

+0

Thậm chí nếu nó không khả dụng, OP chỉ có thể thêm lệnh gọi lại trước khi đặt giá trị. BillItems không cần phải biết ID của riêng họ hoặc ID của Hóa đơn gốc để xác thực. – hornairs

1

tôi "cố định" nó bằng cách thiết lập cha mẹ trong một callback:

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 

Phương pháp set_nest đã làm các trick. Chúc nó đạt tiêu chuẩn với accept_nested_attributes_for.

7

Trong Rails 4 (không thử nghiệm trên phiên bản trước đó), bạn có thể truy cập vào các mô hình mẹ bằng cách thiết lập các tùy chọn inverse_of trên has_many hoặc has_one:

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

    accepts_nested_attributes_for :bill_items 
end 

Tài liệu: Bi-directional associations

+0

Đây là câu trả lời đúng cho đường ray 4 – Abs