Cosa Choco detto funziona se si desidera un array non un'istanza record attivo. Se si desidera un'istanza record attiva, fare:
User.where(id: 5).select(:id, :first_name).take
Ecco alcune ulteriori informazioni. Non sono sicuro di quanto tu sappia/non so, quindi presumo che tu sappia di meno piuttosto che di più.
Immagino che tu ti renda conto che quello che stai facendo sopra è il concatenamento del metodo, cioè, stai chiamando un metodo, quindi chiama un altro metodo sul risultato del primo metodo. Per esempio:
User.find_by(id: 5).attributes.slice('id', 'first_name')
Stai chiamando il metodo find_by_id
sulla classe User
. Questo metodo restituirà un'istanza della classe User
(ovvero un'istanza di record attiva). Quell'istanza ha un metodo chiamato attributes
, che chiami. Il metodo attributes
restituisce un'istanza della classe Hash
, che rappresenta i campi nell'istanza record attiva precedente. Hash
ha un metodo slice
, che si chiama a turno. Il metodo slice
restituisce un'altra istanza di Hash
, contenente il sottoinsieme di campi specificato.
Quindi, il concetto da chiarire è che quando si concatenano i metodi, non si chiama ogni metodo successivo sulla stessa cosa: lo si chiama sul valore di ritorno del metodo precedente nella catena .
OK, quindi con quella fuori strada:
Tutti i metodi find
hanno lo scopo di interrogare il database e restituire una singola istanza di un modello Active Record, o un array di rubino pianura che contiene più istanze di Active Record Modelli.
Un sacco di altri metodi - select
, where
, ecc. NON colpiscono immediatamente il database e NON intendono restituire un'istanza di record attiva. Tutti restituiscono un'istanza di ActiveRecord::Relation
.Un ActiveRecord::Relation
è un po 'come un potenziale gruppo di record che soddisfano determinate condizioni - ed è possibile aggiungere ulteriori condizioni ad esso. È come una "query del database in attesa di accadere" o una "query del database che potrebbe essere o non essere ancora avvenuta".
Quando si chiama un metodo come where
, order
, o select
su ActiveRecord::Relation
, restituirà un'istanza di ActiveRecord::Relation
, il che significa che hai un'istanza della stessa classe, e può metodi di catena da quella classe piacevolmente ad esempio: User.where(name: 'Fred').select(:id, :name).order('name ASC')
l'istanza di ActiveRecord::Relation
sarà molto intelligente, e non preoccuparsi di colpire il database fino a quando si chiama un metodo che indica chiaramente si desidera che i record ora - come each
, all
, take
, ecc
Quindi, sono andato più lungo del previsto qui, quindi concluderò. Ecco il codice che ho prima accennato, con un panne, pesantemente commentato spiegazione di seguito:
User.where(id: 5).select(:id, :first_name).take
scomponendola:
my_relation = User.where(id: 5)
# The database will not have been hit yet - my_relation
# is a query waiting to happen
my_second_relation = my_relation.select(:id, :first_name)
# The database has STILL not been hit.
# the relation now contains both the conditions
# from the previous my_relation, and the new 'select'
# criteria we specified
my_user = my_second_relation.take
# OK, 'take' means we want the first record
# matching all our criteria,
# so my_second_relation will hit the database
# to get it, and then return an Active Record
# instance (ie, an instance of the User class)
Wow ... sono andato più a lungo del previsto. Spero che alcuni di essi siano stati utili!
Come si fa a distinguere un utente ** ** ospite da un utente normale ** **? – Pavan