52

Rails ha un'associazione has_one :through che consente di impostare un'associazione one-to-one con un terzo modello passando attraverso un secondo modello. Qual è il vero uso di questo oltre a creare un'associazione di collegamenti, che altrimenti sarebbe un ulteriore passo in più.Rails has_one: tramite associazione

Prendendo questo esempio dalle rotaie guide:

class Supplier < ActiveRecord::Base 
    has_one :account 
    has_one :account_history, :through => :account 
end 

class Account < ActiveRecord::Base 
    belongs_to :supplier 
    has_one :account_history 
end 

class AccountHistory < ActiveRecord::Base 
    belongs_to :account 
end 

potrebbe permetterci di fare qualcosa di simile:

supplier.account_history 

che altrimenti raggiungibile come:

supplier.account.history 

se si tratta di solo per un accesso più semplice quindi tecnicamente potrebbe esserci un'associazione one-to-one tha t collega un modello con un ennesimo modello che passa attraverso i modelli n-1 per un accesso più semplice. C'è qualcos'altro che mi manca oltre alla scorciatoia?

risposta

47
  1. Logic, OK potrebbe sembrare un po 'debole per questo, ma sarebbe logico dire che "ho un fornitore che ha un account con me, voglio vedere tutta la storia conto di questo fornitore ", quindi per me è logico poter accedere direttamente alla cronologia dell'account dal fornitore.

  2. efficienza, questo per me è il motivo principale che userei :through, semplicemente perché questo emette una join piuttosto che chiamare il fornitore, e quindi rappresentano, e poi account_history. notato il numero di chiamate al database?

    • utilizzando :through, 1 chiamata per ottenere il fornitore, 1 chiamata per ottenere account_history (automaticamente rotaie utilizza :join per recuperare tramite l'account)

    • con una normale associazione, 1 chiamata per ottenere il fornitore, 1 chiamata a ottenere account e 1 chiamata per ottenere account_history

Questo è quello che penso =) spero che aiuta!

+2

Penso che l'argomento della logica sia piuttosto valido. Sembra più naturale dirlo, procurami la cronologia dell'account di questo fornitore e non la cronologia dell'account del fornitore. Molto sottile ma ancora più facile da ricordare considerando la filosofia di Ruby/Rails di frasi fluenti piuttosto che di codice. So che possiamo vedere le effettive query DB emesse, ma Rails specifica come queste chiamate di metodo si tradurrebbero in SQL? – Anurag

+10

Ciò evita anche di violare la legge di Demeter. –

+2

@ TomCrayford, non vedo davvero come funziona. Questo non rende la relazione meno diretta? –

6
  • associazione inversa: considerare l'utente-appartenenza-gruppo classica situazione. Se un utente può essere membro in molti gruppi, un gruppo ha molti membri o utenti e un utente ha molti gruppi. Ma se l'utente può essere solo un membro di un gruppo, il gruppo ha ancora molti membri: class User has_one :group, :through => :membership ma class Group has_many :members, :through => memberships. Il modello intermedio membership è utile per tenere traccia della relazione inversa.

  • espandibilità: un rapporto has_one :through può facilmente essere ampliato ed esteso ad un rapporto has_many :through

7

Mi sorprende che nessuno ha toccato Associazione Oggetti.

Un rapporto has_many (o has_one) :through facilita l'uso del association object pattern che è quando si hanno due cose sono collegati tra loro, e che relazione stessa ha attributi (cioè una data in cui è stata effettuata l'associazione o quando scade).

Questo è considered by some per essere una buona alternativa all'helper ActiveRecord has_and_belongs_to_many. Il ragionamento alla base di questo è che è molto probabile che dovrai cambiare la natura dell'associazione o aggiungerla ad essa, e quando sei un paio di mesi in un progetto, questo può essere molto doloroso se la relazione fosse inizialmente impostata come a has_and_belongs_to_many (il secondo link entra in dettaglio). Se è impostato inizialmente usando una relazione has_many :through, dopo un paio di mesi nel progetto è facile rinominare il modello di join o aggiungere attributi ad esso, rendendo più semplice per gli sviluppatori rispondere ai mutevoli requisiti. Pianificare il cambiamento.