2012-12-08 9 views
29

Czy istnieje krótsza droga wykonać następujące czynności (Skrót do wyskubywania dwóch atrybutów z obiektu ActiveRecord?

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

Userhas_many pracowników. Obie klasy dziedziczą ActiveRecord::Base.

Dwie rzeczy nie lubię o powyższym

  1. To ładuje pracowników do pamięci przed mapowaniem,
  2. To jest pełne (subiektywne, jak sądzę)

Czy istnieje lepszy sposób?

+0

jakikolwiek powód, aby zbudować hash zamiast pracować z wystąpień pracownika (tylko z tych dwóch kolumn ładowanych z 'select')? – tokland

+0

Tak, wiem, że to trochę wymyślne. Właśnie zauważyłem metodę "pluck" i wydaje mi się, że powinno być zrzucenie więcej niż jednego atrybutu. –

+1

istnieje otwarty problem dla zrzutu z więcej niż 1 atrybut: https://github.com/rails/rails/pull/5472. Sprawdź też: https://github.com/ernie/valium – tokland

Odpowiedz

38

UPDATE: Roztwór

SEE @ jamesharker to: od ActiveRecord> = 4, pluck przyjmuje wiele parametry:

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

poprzedniej odpowiedzi:

dla pojedynczej kolumny szyn > = 3,2, możesz zrobić:

@user.employees.pluck(:name) 

... ale jak trzeba zrywać dwa atrybuty, można zrobić:

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

jeśli naprawdę potrzebne działanie niższego poziomu, wystarczy spojrzeć na source of #pluck, który wykorzystuje select_all

+2

nie wybiera się wziąć tablicę atrybutów? – tokland

+1

oh, racja, zapomniałem –

+0

Dziękuję za to. Przychodzisz z aplikacji 4.x do aplikacji 3.2. Zapomniałem o tym. Waliłem głową o ścianę. Arghhhhh dla starych aplikacji. – covard

32

W ActiveRecord> = 4 pluck akceptuje wiele argumentów więc przykład ten stałby się:

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

W prawo, ale to zwraca 'tablicę' bez kluczy; np .: [[1, 'Pete'], [[2, 'Fred']] "w przeciwieństwie do' hash', którego OP szuka: '[{id: 1, name: 'Pete'}, { id: 2, name: 'Fred'}] ' –

+0

Jakieś idei, jak zdobyć [{id: 1, nazwa: 'Pete'}, {id: 2, imię: 'Fred'}] bez mapy? –

0

Dodaj tę poprawkę małpa która zapewnia Multi kolumny zrywać funkcjonalność w 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 

Zmiana nazwy metody z pluck do pluck_all jeśli nie chcą zastępuje oryginalną funkcję pluck

0

Pod względem robienia metody szyn 3, która zachowuje się tak samo jak zrywanie Rails 4 z wieloma kolumnami. To wyprowadza podobną tablicę (zamiast hashowanej kolekcji wartości kluczy). Powinno to uratować trochę bólu, jeśli kiedykolwiek podejdziesz do aktualizacji i chcesz oczyścić kod.

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 

Stojąc na ramionach olbrzymów i wszystko

0

Sposób pluck_all działa dobrze dopóki ja jadę do aktualizacji z 3.2 do Rails Rails 4.

Oto perełka pluck_all aby rozwiązać ten problem, dzięki czemu wsparcie pluck_all metoda nie tylko w Rails 3, ale w szynach 4 i Rails 5. nadzieję, że pomoże tym, którzy idą do uaktualnienia wersji Rails.

0

Inną opcją jest:

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

mogę sobie wyobrazić, że wolisz mieć symbolizowane klucze. Jeśli tak jest, użyj metody #symbolize_keys.

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

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

Powiązane problemy