Rails: tạo trên liên kết has_one


100

Xin chào (người mới chơi Rails lớn ở đây), tôi có các mô hình sau:

class Shop < ActiveRecord::Base
  belongs_to :user
  validates_uniqueness_of :title, :user_id, :message => "is already being used"
end

class User < ActiveRecord::Base
  has_one :shop, :dependent => :destroy
end

Khi tôi chuẩn bị tạo một cửa hàng mới, tôi gặp lỗi sau:

private method `create' called for nil:NilClass

Đây là bộ điều khiển của tôi:

@user = current_user
@shop = @user.shop.create(params[:shop])

Tôi đã thử các biến thể khác nhau bằng cách đọc hướng dẫn và hướng dẫn ở đây và ở đó, nhưng tôi bối rối hơn trước và không thể làm cho nó hoạt động. Mọi sự trợ giúp sẽ rất được trân trọng.


Đã chỉnh sửa tiêu đề câu hỏi để phản ánh câu hỏi. Bản sao của việc sử dụng bản dựng với một liên kết has_one trong đường ray
Marc-André La xui xẻo

1
bạn cũng có thể sử dụng@user.build_shop(params)
ImranNaqvi

Câu trả lời:


123

Trước hết, đây là cách làm những gì bạn muốn:

@user = current_user
@shop = Shop.create(params[:shop])
@user.shop = @shop

Bây giờ đây là lý do tại sao phiên bản của bạn không hoạt động:

Bạn có thể nghĩ rằng điều này có thể hiệu quả bởi vì nếu Người dùng có has_manymối quan hệ với Shop, @user.shops.create(params[:shop]) nó sẽ hoạt động. Tuy nhiên có một sự khác biệt lớn giữa has_manyquan hệ và has_onequan hệ:

Với một has_manyquan hệ, shopstrả về một đối tượng bộ sưu tập ActiveRecord, đối tượng này có các phương thức mà bạn có thể sử dụng để thêm và xóa cửa hàng đến / khỏi người dùng. Một trong những phương pháp đó là createtạo một cửa hàng mới và thêm nó vào người dùng.

Với một has_onemối quan hệ, bạn không lấy lại một đối tượng bộ sưu tập như vậy, mà chỉ đơn giản là đối tượng Cửa hàng thuộc về người dùng - hoặc không nếu người dùng chưa có cửa hàng. Vì cả đối tượng Shop và nil đều không có createphương thức nên bạn không thể sử dụng createcách này với các has_onequan hệ.


Cảm ơn câu trả lời của bạn, sepp2k. Bây giờ tôi thấy tại sao mã của tôi không thể hoạt động.
Neko

118
Bạn cũng có thể sử dụng @user.create_shop(params[:shop]). Xem các phương pháp được thêm bởi has_one .
nates

Câu trả lời được chọn hoạt động, nhưng giải pháp @nates cũng hoạt động. +1 cho cả hai người.
nfriend21

+1 cho câu trả lời vì tôi cũng tự hỏi như vậy, +1 cho câu trả lời để giải thích tại sao lại như vậy và +1 cho nhận xét để đưa ra giải pháp tốt nhất.
deivid

224

Một cách ngắn gọn hơn để làm điều này là:

@user.create_shop(params[:shop])

Xem các phương thức được thêm bởi has_one trong hướng dẫn Ruby on Rails.


6
Đây chắc chắn là cách tiếp cận tốt hơn
Magnum

7
Hãy lưu ý rằng nếu bạn tạo_shop nhiều hơn một lần nó sẽ xóa cửa hàng trước đó. Ví dụ: nếu bạn chạy @user.create_shop(params[:shop_one_info])nó sẽ tạo shop_one, NHƯNG nếu bạn chạy @user.create_shop(params[:shop_two_info])nó sẽ xóa cửa hàng đầu tiên và tạo cửa hàng thứ hai.
ecoding

Nhận xét trên về việc xóa quán trước là dành cho Rails 3.2.18, không biết có thêm phiên bản gần đây không. Không thể chỉnh sửa nhận xét sau 5 phút -_-
ecoding

Đã tìm thấy giải pháp, tôi không đặt tính duy nhất trên mô hình được liên kết, vì vậy hãy đảm bảo bạn làm như cách thiết lập nó trong mô hình Shop của ví dụ này.
ecoding

bạn có thể sử dụng alse@user.build_shop(params)
ImranNaqvi

7

Hai cách khác nếu bạn muốn savethay vì create:

shop = @user.build_shop
shop.save

shop = Show.new
shop.user = @user
shop.save

1

Chỉ để thêm vào các câu trả lời ở trên -

@user.create_shop(params[:shop])

Cú pháp trên tạo bản ghi mới nhưng sau đó nó xóa bản ghi hiện có tương tự.

Ngoài ra, nếu bạn không muốn kích hoạt lệnh gọi lại xóa

Shop.create(user_id: user.id, title: 'Some unique title')

Chủ đề này có thể hữu ích. Bấm vào đây

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.