Rails: Sử dụng bản dựng với liên kết has_one trong rails


143

Trong ví dụ này, tôi tạo một userkhông có profile, sau đó tạo một profilecho người dùng đó. Tôi đã thử sử dụng xây dựng với một has_onehiệp hội nhưng điều đó đã nổ tung. Cách duy nhất tôi thấy làm việc này là sử dụng has_many. Điều userđược cho là chỉ có nhiều nhất là một profile.

Tôi đã cố gắng này. Tôi có:

class User < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

Nhưng khi tôi làm:

user.build_profile 

Tôi nhận được lỗi:

ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'profiles.user_id' in 'where clause': SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4)  LIMIT 1

Có cách nào trong đường ray để có 0 hoặc 1 liên kết không?


chính xác những gì bạn đã cố gắng? bạn có thể, xin vui lòng, gửi một số mã?
Ju Nogueira

Câu trả lời:


359

Các buildchữ ký phương pháp là khác nhau cho has_onehas_manyhiệp hội.

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

Cú pháp xây dựng cho has_manyliên kết:

user.messages.build

Cú pháp xây dựng cho has_oneliên kết:

user.build_profile  # this will work

user.profile.build  # this will throw error

Đọc tài liệuhas_one hiệp hội để biết thêm chi tiết.


28
Cú pháp khác nhau cho has_one luôn khiến tôi bị ... chết tiệt!
Thiên hà

11
Thật buồn cười khi câu trả lời được xếp hạng và chấp nhận hàng đầu ở đây đang trả lời một câu hỏi khác với câu hỏi mà OP đã hỏi.
Ajedi32

Giả sử nếu người dùng thuộc về hồ sơ (có nghĩa là bảng người dùng có Foreign_key profile_id trong bảng của nó) thì việc xây dựng hồ sơ cho người dùng sẽ hoạt động như đã đề cập ở trên, nhưng đối với hành động mới chỉ user.build_profile để chỉnh sửa user.build_profile if user.profile.nil? và nếu bạn muốn xây dựng hồ sơ trong khi tạo người dùng thì hãy viết accepts_nested_attributes_for :profileđiều này vào Mô hình người dùng. và ở dạng mà người dùng đang được tạo, hãy viết <%= f.simple_fields_for :profile do |p| %>cái này và tiếp tục.
sốt sắng

nhưng tại sao hành vi khác nhau này được giữ cho has_one hoặc has_many? Sẽ có một số lý do trong khi thiết kế, tôi nghĩ và mong đợi.
tò mò

@ Ajedi32 câu trả lời phù hợp với tiêu đề của câu hỏi nhưng không phải là cơ thể. Cho rằng đây ( build_<association>) là một hành vi khá kỳ lạ và bất ngờ trong Rails, có rất nhiều người tìm kiếm câu trả lời này hơn câu trả lời của các câu hỏi thực tế, nếu bạn hiểu ý tôi là gì.
Max Williams

19

Hãy nhìn vào thông báo lỗi. Nó nói với bạn rằng bạn không có cột bắt buộc user_idtrong bảng hồ sơ . Thiết lập các mối quan hệ trong mô hình chỉ là một phần của câu trả lời.

Bạn cũng cần tạo một di chuyển thêm user_idcột vào bảng hồ sơ. Rails mong đợi điều này sẽ ở đó và nếu không, bạn không thể truy cập hồ sơ.

Để biết thêm thông tin xin vui lòng xem liên kết này:

Khái niệm cơ bản về hiệp hội


1
Tôi chỉ tìm ra vấn đề của tôi. Cuốn sách tôi đang học không giải thích rõ về việc tạo khóa ngoại. Tôi đã tạo một di chuyển mới có thêm khóa ngoại vào mô hình của tôi. cảm ơn.
đặc biệt

Bạn có cần phải tự tạo cột mỗi lần không? Tôi đã có ý tưởng rằng nó đã xảy ra tự động. Tôi không biết tôi đã có ý tưởng đó ở đâu.
Rimian

Bạn có thể thêm cột khi tạo mô hình bằng dòng lệnh, đại loại như thế rails g model profile user:references:index address:string bio:text.
duykhoa

1

Tùy thuộc vào trường hợp sử dụng, có thể thuận tiện để bọc phương thức và tự động xây dựng liên kết khi không tìm thấy.

old_profile = instance_method(:profile)
define_method(:profile) do
  old_profile.bind(self).call || build_profile
end

bây giờ gọi #profilephương thức sẽ trả về hồ sơ liên quan hoặc xây dựng một thể hiện mới.

nguồn: Khi khỉ vá một phương thức, bạn có thể gọi phương thức bị ghi đè từ triển khai mới không?


1
trong đường ray hiện tại (được thử nghiệm vào ngày 6.0.2.2), bạn có thể đơn giản hóa việc này thành : def profile; super || build_profile; end.
glasz

-14

Nó nên là một has_one. Nếu buildkhông hoạt động, bạn chỉ có thể sử dụng new:

ModelName.new( :owner => @owner )

giống như

@owner.model_names.build

11
Điều này không giống nhau: nếu bạn tạo một model_name mới với bản dựng, khi @owner được lưu thì model_name mới cũng sẽ được lưu. Vì vậy, bạn có thể sử dụng bản dựng để tạo ra cha mẹ và con cái sẽ được lưu lại với nhau. Đây không phải là trường hợp nếu bạn tạo một model_name với .new
Max Williams
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.