come aggiungere record a has_many: tramite associazione in rails


94
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

Come aggiungo al Agentsmodello perCustomer ?

È questo il modo migliore?

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

Quanto sopra funziona bene dalla console, tuttavia, non so come ottenerlo nell'applicazione reale.

Immagina che venga compilato un modulo per il cliente che prende anche house_idcome input. Quindi faccio quanto segue nel mio controller?

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

Nel complesso sono confuso su come aggiungere record nella has_many :throughtabella?


In quale controller memorizzereste la funzione "crea"?
— Tobias Kolb

Risposte:


163

Penso che tu possa semplicemente fare questo:

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

O quando si crea una nuova casa per un cliente:

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

Puoi anche aggiungere tramite ID:

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

16
FYI: non puoi creare la casa associata a meno che il genitore non sia già salvato.
— Ricardo Otero

Questa deve essere la soluzione più elegante a questo problema che ho incontrato. +1 per te.
— Daniel Bonnell,

@RicardoOtero immagino che possiamo usare buildinvece di create?
— Karan

@Mischa come dovrei gestire l'errore se House.find (params [: house_id]) è nullo .. ho ricevuto un errore di TypeMismatch se params [: house_id] è nullo .. sto già usando rescue. ma c'è un modo migliore .. ??
— Vishal

1
Ho osservato che l'uso di <<operator fa l'inserimento due volte in alcuni casi. Quindi il createmetodo è il modo migliore.
— Scambia il

77

"Il modo migliore" dipende dalle tue esigenze e da ciò che ti sembra più comodo. La confusione deriva dalle differenze di comportamento ActiveRecord del newe createmetodi e l' <<operatore.

Il newmetodo

newnon aggiungerà un record di associazione per te. Devi creare Housee Agentregistrare da solo:

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

Nota che @cust.houses.newe House.newsono effettivamente gli stessi perché devi creare il Agentrecord in entrambi i casi.

L' <<operatore

Come menzionato da Mischa, puoi anche utilizzare l' <<operatore sulla raccolta. Questo costruirà solo il Agentmodello per te, devi costruire il Housemodello:

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

Il createmetodo

createcostruirà sia Housee Agentrecord per voi, ma è necessario trovare il Agentmodello di se avete intenzione di tornare che alla vista o di api:

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

Come nota finale, se vuoi che le eccezioni vengano sollevate durante la creazione, houseusa invece gli operatori bang (ad esempio new!e create!).


2
La riga dovrebbe invece agent = @cust.houses.find(house.id)leggere agent = @cust.agents.find(house.id)? La agentvariabile nel "nuovo metodo" è diversa da quella agentnegli ultimi esempi. Potrebbe creare un po 'di confusione per le persone che lavorano con attributi aggiuntivi nella tabella di join.
— Vaughan

puoi approfondire il recupero dei dati dalla tabella congiunta Agenti senza avere N + 1 bug di esempio che mostra tutte le case e gli agenti corrispondenti per il dato cliente
— Ankita.P

6

Un altro modo per aggiungere associazioni è utilizzare le colonne della chiave esterna:

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

Oppure utilizza i nomi esatti delle colonne, passando l'ID del record associato invece del record.

agent.house_id = house.id
agent.customer_id = customer.id
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.