Rails: buat di asosiasi has_one


100

Hai (pemula Rails besar di sini), saya memiliki model berikut:

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

dan

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

Ketika saya akan membuat toko baru, saya mendapatkan kesalahan berikut:

private method `create' called for nil:NilClass

Ini pengontrol saya:

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

Saya telah mencoba variasi yang berbeda dengan membaca panduan dan tutorial di sana-sini, tetapi saya lebih bingung daripada sebelumnya dan tidak dapat membuatnya berfungsi. Bantuan apa pun akan sangat dihargai.


Judul pertanyaan diedit untuk mencerminkan pertanyaan. Duplikat Menggunakan build dengan asosiasi has_one di rel
— Marc-AndrĂ© Lafortune

1
Anda juga dapat menggunakan@user.build_shop(params)
— ImranNaqvi

Jawaban:


123

Pertama-tama, berikut ini cara melakukan apa yang Anda inginkan:

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

Sekarang, inilah mengapa versi Anda tidak berfungsi:

Anda mungkin berpikir bahwa ini mungkin berhasil karena jika Pengguna memiliki has_manyhubungan dengan Toko, @user.shops.create(params[:shop]) akan berhasil. Namun ada perbedaan besar antara has_manyrelasi dan has_onerelasi:

Dengan suatu has_manyrelasi, shopsmengembalikan objek koleksi ActiveRecord, yang memiliki metode yang dapat Anda gunakan untuk menambah dan menghapus toko ke / dari pengguna. Salah satu metode tersebut adalah create, yang membuat toko baru dan menambahkannya ke pengguna.

Dengan has_onerelasi, Anda tidak akan mendapatkan kembali objek koleksi seperti itu, tetapi cukup objek Toko yang dimiliki pengguna - atau nol jika pengguna belum memiliki toko. Karena baik objek Shop maupun nil tidak memiliki createmetode, Anda tidak dapat menggunakan createcara ini dengan has_onerelasi.


Terima kasih atas jawaban Anda, sepp2k. Sekarang saya mengerti mengapa kode saya tidak dapat berfungsi.
— Neko

118
Anda juga bisa menggunakan @user.create_shop(params[:shop]). Lihat metode yang ditambahkan oleh has_one .
— Nates

Jawaban yang dipilih berfungsi, tetapi solusi @nates juga berfungsi. +1 untuk Anda berdua.
— nfriend21

+1 untuk jawaban karena saya bertanya-tanya hal yang sama, +1 untuk jawaban untuk menjelaskan mengapa ini dan +1 untuk komentar untuk memberikan solusi terbaik.
— membagi

224

Cara yang lebih ringkas untuk melakukannya adalah dengan:

@user.create_shop(params[:shop])

Lihat metode yang ditambahkan oleh has_one di panduan Ruby on Rails.


6
Ini jelas merupakan pendekatan yang lebih baik
— Magnum

7
Berhati-hatilah jika Anda membuat toko lebih dari sekali, itu akan menghapus toko sebelumnya. Misalnya jika Anda menjalankannya @user.create_shop(params[:shop_one_info])akan membuat shop_one, TETAPI jika dijalankan @user.create_shop(params[:shop_two_info])itu akan menghapus toko pertama dan membuat yang kedua.
— ecoding5

Komentar di atas tentang menghapus toko sebelumnya adalah untuk Rails 3.2.18, tidak tahu tentang versi yang lebih baru. Tidak dapat mengedit komentar setelah 5 menit -_-
— ecoding5

Menemukan solusi, saya tidak menetapkan keunikan pada model terkait, jadi pastikan Anda melakukan seperti yang diatur dalam model Toko contoh ini.
— ecoding5

Anda juga dapat menggunakan@user.build_shop(params)
— ImranNaqvi

7

Dua cara lagi jika Anda mau, savebukan create:

shop = @user.build_shop
shop.save

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

1

Hanya untuk menambah jawaban di atas -

@user.create_shop(params[:shop])

Sintaks di atas membuat rekaman baru tetapi kemudian menghapus rekaman serupa yang sudah ada.

Alternatifnya, jika Anda tidak ingin memicu delete callback

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

Utas ini mungkin bisa membantu. Klik disini

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.