2012-12-08 16 views
29

C'è un modo più breve per effettuare le seguenti operazioni (Scorciatoia per prelevare due attributi da un oggetto ActiveRecord?

@user.employees.map { |e| { id: e.id, name: e.name } } 
# => [{ id: 1, name: 'Pete' }, { id: 2, name: 'Fred' }] 

Userhas_many dipendenti. Entrambe le classi ereditano da ActiveRecord::Base.

due cose che non mi piace di quanto sopra

  1. E ' carica gli impiegati in memoria prima della mappatura,
  2. È prolisso (suppongo soggettivo)

C'è un modo migliore?

+0

alcuna ragione per costruire un hash invece di lavorare con le istanze dei dipendenti (con i soli due colonne caricate con un 'select')? – tokland

+0

Sì, lo so che è un po 'forzato. Ho appena notato il metodo 'pluck' e mi sembra che ci dovrebbe essere una cotta per più di un attributo. –

+1

c'è un problema aperto con più di 1 attributo: https://github.com/rails/rails/pull/5472. Inoltre, controlla questo: https://github.com/ernie/valium – tokland

risposta

38

UPDATE: soluzione

vedere @ di jamesharker: da ActiveRecord> = 4, pluck accetta più argomenti:

@user.employees.pluck(:id, :name) 

risposta precedente:

per una singola colonna in rotaie > = 3,2, puoi fare:

@user.employees.pluck(:name) 

... ma come si deve cogliere due attributi, si può fare:

@user.employees.select([:id, :name]).map {|e| {id: e.id, name: e.name} } 
# or map &:attributes, maybe 

se realmente bisogno funzionamento di livello inferiore, basta guardare il source of #pluck, che utilizza select_all

+2

non seleziona prendere una matrice di attributi? – tokland

+1

oh, giusto, l'ho dimenticato –

+0

Grazie per questo. Proveniente da un'app 4.x a un'app 3.2. Dimenticato di questo Stavo sbattendo la testa contro il muro. Arghhhhh per vecchie app. – covard

32

In ActiveRecord> = 4 pluck accetta più argomenti in modo da questo esempio diventerebbe:

@user.employees.pluck(:id, :name) 
+5

A destra, ma restituisce un 'array' senza le chiavi; ad esempio: '[[1, 'Pete'], [[2, 'Fred']]' al contrario di un 'hash' che OP sta cercando:' [{id: 1, nome: 'Pete'}, { id: 2, nome: 'Fred'}] ' –

+0

Qualsiasi ideia su come ottenere [{id: 1, nome: 'Pete'}, {id: 2, nome: 'Fred'}] senza mappa? –

0

Aggiungi questa patch scimmia che prevede il multi colonne colgono funzionalità in Rails 3.

# config/initializers/pluck_all.rb 

if Rails.version[0] == '3' 
    ActiveRecord::Relation.class_eval do 
    def pluck(*args) 
     args.map! do |column_name| 
     if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s) 
      "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}" 
     else 
      column_name.to_s 
     end 
     end 

     relation = clone 
     relation.select_values = args 
     klass.connection.select_all(relation.arel).map! do |attributes| 
     initialized_attributes = klass.initialize_attributes(attributes) 
     attributes.map do |key, attr| 
      klass.type_cast_attribute(key, initialized_attributes) 
     end 
     end 
    end 
    end 
end 

Rinominare il metodo pluck-pluck_all se non volete sostituisce la funzionalità originale pluck

0

In termini di creazione di un metodo di rotaie 3 che si comporta allo stesso modo in cui il Rails 4 si piega con più colonne. Questo produce un array simile (piuttosto che una raccolta di valori chiave con hash). Questo dovrebbe risparmiare un po 'di dolore se mai venissi ad aggiornare e volessi ripulire il codice.

module ActiveRecord 
    class Relation 
    def pluck_all(*args) 
     args.map! do |column_name| 
     if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s) 
      "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}" 
     else 
      column_name.to_s 
     end 
     end 

     relation = clone 
     relation.select_values = args 
     klass.connection.select_all(relation.arel).map! do |attributes| 
     initialized_attributes = klass.initialize_attributes(attributes) 
     attributes.map do |key, attribute| 
      klass.type_cast_attribute(key, initialized_attributes) 
     end 
     end 
    end 
    end 
end 

In piedi sulle spalle dei giganti e tutti

0

Il metodo pluck_all funzionato bene fino a quando ho intenzione di eseguire l'aggiornamento da Rails 3.2 a Rails 4.

Ecco una gemma pluck_all per risolvere questo problema, rendendo il supporto del metodo pluck_all non solo in Rails 3 ma in Rails 4 e Rails 5. Spero che questo possa aiutare coloro che stanno per aggiornare la versione dei binari.

0

Un'altra opzione è quella di:

@user.employees.select(:id, :name).as_json 
#=> [{"id" => 1, "name" => "Pete"}, {"id" => 2, "name" => "Fred"}] 

posso immaginare che si preferisce avere le chiavi simbolizzati. In tal caso, utilizzare il metodo #symbolize_keys.

@user.employees.select(:id, :name).as_json.map(&:symbolize_keys) 
#=> [{id: 1, name: "Pete"}, {id: 2, name: "Fred"}] 

See: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json

Problemi correlati