2012-12-08 87 views
29

有一個較短的方式做以下(從ActiveRecord對象中採集兩個屬性的快捷方式?

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

Userhas_many員工。這兩個類從ActiveRecord::Base繼承。

兩件事情我不喜歡上面的

  1. 它在映射之前將員工加載到內存中,
  2. 它是冗長的(主觀我猜)

有沒有更好的方法?

+0

任何理由建立一個哈希值,而不是與員工的工作情況(經載有一個'select'只有兩列)? – tokland

+0

是的,我知道這是有點人爲的。我只注意到'pluck'方法,在我看來,應該有一個以上的屬性採摘。 –

+1

對於擁有超過1個屬性的摘錄有一個問題:https://github.com/rails/rails/pull/5472。另外,請查看:https://github.com/ernie/valium – tokland

回答

38

UPDATE:

見@ jamesharker的解決方案:從ActiveRecord的> = 4,pluck接受多個參數:

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

以前的答案:

在軌道的單個列> = 3.2,你可以這樣做:

@user.employees.pluck(:name) 

...但你一定要摘下兩個屬性,你可以這樣做:

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

,如果你真的需要較低級別的操作,只是看source of #pluck,使用select_all

+2

不選擇取數組屬性? – tokland

+1

哦,沒錯,忘了吧 –

+0

謝謝你。從4.x應用程序到3.2應用程序。忘了這個。我的頭撞在牆上。 Arghhhhh舊的應用程序。 – covard

32

在ActiveRecord的> = 4 pluck接受多個參數,以便該實施例中會變得:

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

對,但是返回沒有鍵的'array';例如:[[1,'Pete'],[[2,'Fred']],而不是OP尋找的'hash':'[{id:1,name:'Pete'},{ id:2,name:'Fred'}]' –

+0

如何獲得[{id:1,name:'Pete'},{id:2,name:'Fred'}] without map? –

0

添加這隻猴子補丁,它提供了多列掐在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 

重命名從pluck的方法pluck_all如果你不想覆蓋原始的pluck功能

0

就製作軌跡3方法而言,軌跡3與多列軌跡相同。這會輸出一個類似的數組(而不是散列鍵值集合)。如果你升級並想清理代碼,這應該會節省一些痛苦。

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 

站在巨人的肩膀上,所有

0

pluck_all方法效果很好,直到我準備從Rails的3.2升級到Rails 4。

這是一個gem pluck_all來解決這個問題,使得pluck_all方法不僅支持Rails 3,而且支持Rails 4和Rails 5.希望這可以幫助那些正在升級rails版本的人。

0

另一種選擇是:

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

我可以想像,你寧願有象徵鍵。 如果是這種情況,請使用#symbolize_keys方法。

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

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

相關問題