cara menambahkan catatan ke has_many: melalui pengaitan di rel


97
class Agents << ActiveRecord::Base
  belongs_to :customer
  belongs_to :house
end

class Customer << ActiveRecord::Base
  has_many :agents
  has_many :houses, through: :agents
end

class House << ActiveRecord::Base
  has_many :agents
  has_many :customers, through: :agents
end

Bagaimana cara menambahkan Agentsmodel Customer?

Apakah ini cara terbaik?

Customer.find(1).agents.create(customer_id: 1, house_id: 1)

Di atas berfungsi dengan baik dari konsol namun, saya tidak tahu bagaimana mencapai ini dalam aplikasi sebenarnya.

Bayangkan sebuah formulir diisi untuk pelanggan yang juga mengambil house_idmasukan. Lalu apakah saya melakukan hal berikut di pengontrol saya?

def create 
  @customer = Customer.new(params[:customer])
  @customer.agents.create(customer_id: @customer.id, house_id: params[:house_id])
  @customer.save
end

Secara keseluruhan saya bingung bagaimana cara menambahkan catatan di has_many :throughtabel?


Di pengontrol mana Anda akan menyimpan fungsi "create"?
— Tobias Kolb

Jawaban:


166

Saya pikir Anda cukup melakukan ini:

 @cust = Customer.new(params[:customer])
 @cust.houses << House.find(params[:house_id])

Atau saat membuat rumah baru untuk pelanggan:

 @cust = Customer.new(params[:customer])
 @cust.houses.create(params[:house])

Anda juga dapat menambahkan melalui id:

@cust.house_ids << House.find(params[:house_id])

16
FYI: Anda tidak dapat membuat rumah terkait kecuali orang tuanya sudah disimpan.
— Ricardo Otero

Itu harus menjadi solusi paling elegan untuk masalah ini yang pernah saya temui. 1 untuk Anda.
— Daniel Bonnell

@RicardoOtero Kurasa kita bisa menggunakan yang buildpertama create?
— Karan

@Mischa bagaimana cara menangani error jika House.find (params [: house_id]) nill .. saya mendapat error TypeMismatch jika params [: house_id] nihil .. saya sudah menggunakan penyelamatan. tapi apakah ada cara yang lebih baik .. ??
— Vishal

1
Saya telah mengamati bahwa menggunakan <<operator melakukan penyisipan dua kali dalam kasus tertentu. Jadi createmetode adalah cara terbaik.
— Tukar

78

'Cara terbaik' tergantung pada kebutuhan Anda dan apa yang dirasa paling nyaman. Kebingungan berasal dari perbedaan perilaku ActiveRecord ini dari newdan createmetode dan <<operator.

The newMetode

newtidak akan menambahkan catatan asosiasi untuk Anda. Anda harus membuat Housedan Agentmencatat sendiri:

house = @cust.houses.new(params[:house])
house.save
agent = Agent(customer_id: @cust.id, house_id: house.id)
agent.save

Perhatikan bahwa @cust.houses.newdan House.newsecara efektif sama karena Anda perlu membuat Agentrekaman dalam kedua kasus.

The <<Operator

Seperti yang disebutkan Mischa, Anda juga bisa menggunakan <<operator pada collection. Ini hanya akan membangun Agentmodel untuk Anda, Anda harus membangun Housemodel:

house = House.create(params[:house])
@cust.houses << house
agent = @cust.houses.find(house.id)

The createMetode

createakan membangun keduanya Housedan Agentrecord untuk Anda, tetapi Anda perlu menemukan Agentmodelnya jika Anda ingin mengembalikannya ke view atau api:

house = @cust.houses.create(params[:house])
agent = @cust.agents.where(house: house.id).first

Sebagai catatan terakhir, jika Anda ingin pengecualian dimunculkan saat membuat housegunakan operator bang sebagai gantinya (misalnya new!dan create!).


2
Haruskah baris itu agent = @cust.houses.find(house.id)dibaca agent = @cust.agents.find(house.id)? The agentvariabel dalam "Metode baru" ini berbeda dengan agentpada contoh terakhir. Mungkin membuat kebingungan bagi orang yang bekerja dengan atribut tambahan di tabel gabungan.
— vaughan

dapatkah Anda menguraikan tentang mengambil data dari tabel gabungan Agen tanpa contoh bug N + 1 yang menampilkan semua rumah dan agen terkait untuk pelanggan tertentu
— Ankita.P

6

Cara lain untuk menambahkan asosiasi adalah dengan menggunakan kolom kunci asing:

agent = Agent.new(...)
agent.house = House.find(...)
agent.customer = Customer.find(...)
agent.save

Atau gunakan nama kolom yang tepat, dengan meneruskan ID dari record terkait, bukan record.

agent.house_id = house.id
agent.customer_id = customer.id
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.