2009-07-30 28 views
22

Tôi đã nâng cấp lên Rails 2.3.3 (từ 2.1.x) và tôi đang cố gắng tìm ra phương thức accepts_nested_attributes_for. Tôi có thể sử dụng phương thức để cập nhật các đối tượng lồng nhau hiện có, nhưng tôi không thể sử dụng nó để tạo các đối tượng lồng nhau mới. Với ví dụ contrived:Cách tạo đối tượng lồng nhau bằng cách sử dụng accept_nested_attributes_for

class Product < ActiveRecord::Base 
    has_many :notes 
    accepts_nested_attributes_for :notes 
end 

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id, :body 
end 

Nếu tôi cố gắng tạo ra một mới Product, với một lồng nhau Note, như sau:

params = {:name => 'Test', :notes_attributes => {'0' => {'body' => 'Body'}}} 
p = Product.new(params) 
p.save! 

Nó không hợp lệ với thông điệp:

ActiveRecord::RecordInvalid: Validation failed: Notes product can't be blank 

Tôi hiểu tại sao điều này xảy ra - đó là vì số validates_presence_of :product_id trên lớp Note và bởi vì tại thời điểm lưu bản ghi mới, 012 Đối tượngkhông có số id. Tuy nhiên, tôi không muốn xóa xác thực này; Tôi nghĩ rằng nó sẽ là không chính xác để loại bỏ nó.

Tôi cũng có thể giải quyết vấn đề bằng cách tạo thủ công trước tiên Product và sau đó thêm Note, nhưng điều đó đánh bại sự đơn giản của accepts_nested_attributes_for.

Có cách Rails chuẩn để tạo đối tượng lồng nhau trên bản ghi mới không?

Trả lời

16

Đây là vấn đề phụ thuộc chung, vòng tròn. Có một số existing LightHouse ticket đáng để kiểm tra.

Tôi hy vọng điều này sẽ được cải thiện nhiều trong Rails 3, nhưng trong thời gian chờ đợi, bạn sẽ phải thực hiện giải pháp thay thế. Một giải pháp là thiết lập thuộc tính ảo mà bạn đặt khi lồng nhau để thực hiện xác thực có điều kiện.

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id, :unless => :nested 
    attr_accessor :nested 
end 

Và sau đó bạn sẽ đặt thuộc tính này làm trường ẩn trong biểu mẫu của bạn.

<%= note_form.hidden_field :nested %> 

Điều đó là đủ để có thuộc tính nested được đặt khi tạo ghi chú thông qua biểu mẫu lồng nhau. Chưa được kiểm tra.

+11

Trong Rails 3 vấn đề này được giải quyết bằng cách thêm vào: inverse_of tùy chọn để has_many, has_one và belongs_to. Xem ví dụ http://www.daokaous.com/rails3.0.0_doc/classes/ActiveRecord/Associations/ClassMethods.html#M001988 trong phần "Liên kết hai chiều" –

+2

Tôi đã chọn tắt tính năng xác thực khi: id == nil . Vì điều đó chỉ xảy ra khi viết một bản ghi mới, lồng nhau, tôi hy vọng rằng sẽ an toàn. Odd rằng vấn đề này đã làm cho nó tất cả các cách để 2.3.8. – aceofspades

+3

inverse_of dường như không hoạt động khi cả cha lẫn mẹ của bản ghi không tồn tại, và do đó không có id nào có thể được kiểm tra. Hình như hack lồng nhau này là cách duy nhất thông qua. :( – DGM

3

giải pháp Ryan thực sự là thực sự mát mẻ. Tôi đã đi và làm cho bộ điều khiển của tôi béo hơn để làm tổ này sẽ không phải xuất hiện trong chế độ xem. Chủ yếu là vì quan điểm của tôi đôi khi là json, vì vậy tôi muốn có thể nhận được càng ít càng tốt trong đó.

class Product < ActiveRecord::Base 
    has_many :notes 
    accepts_nested_attributes_for :note 
end 

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id unless :nested 
    attr_accessor :nested 
end 

class ProductController < ApplicationController 

def create 
    if params[:product][:note_attributes] 
     params[:product][:note_attributes].each { |attribute| 
      attribute.merge!({:nested => true}) 
    } 
    end 
    # all the regular create stuff here 
end 
end 
7
+2

điểm rất quan trọng là bạn nên xác thực sự hiện diện của "sản phẩm" không phải "product_id" – kuboon

+0

Tôi nghĩ kuboon có câu trả lời đúng. "sản phẩm", không phải "product_id" cùng với việc thay đổi liên kết trên Sản phẩm thành "has_many: notes, inverse_of:: product" nên thực hiện. – quainjn

Các vấn đề liên quan