44

是否有更短的方法来执行以下操作(

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

User has_many雇员。这两个类都继承自ActiveRecord::Base.

我不喜欢上面的两件事

  1. 它在映射之前将员工加载到内存中,
  2. 它很冗长(我猜是主观的)。

有没有更好的办法?

4

7 回答 7

59

更新:

请参阅@jamesharker 的解决方案:来自 ActiveRecord >= 4,pluck接受多个参数:

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

以前的答案:

对于 rails >= 3.2 中的单列,您可以执行以下操作:

@user.employees.pluck(:name)

...但是由于您必须采摘两个属性,因此您可以这样做:

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

如果您确实需要较低级别的操作,只需查看#pluck 的来源,它使用select_all

于 2012-12-08T11:47:23.917 回答
42

在 ActiveRecord >= 4 pluck接受多个参数,所以这个例子会变成:

@user.employees.pluck(:id, :name)
于 2013-11-21T13:23:12.127 回答
8

如果你被 Rails 3 卡住了,你可以添加这个 .pluck_all扩展: http: //meltingice.net/2013/06/11/pluck-multiple-columns-rails/

于 2014-07-30T10:09:49.687 回答
1

另一种选择是:

@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

于 2017-10-12T12:13:15.553 回答
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_allpluck

于 2016-05-13T03:58:58.377 回答
0

就制作与 Rails 4 相同的 rails 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

站在巨人和所有人的肩膀上

于 2016-05-19T12:53:16.723 回答
0

pluck_all在我从 Rails 3.2 升级到 Rails 4 之前,该方法运行良好。

这是一个 gem pluck_all来解决这个问题,pluck_all不仅在 Rails 3 中,而且在 Rails 4 和 Rails 5 中都支持方法。希望这对那些打算升级 rails 版本的人有所帮助。

于 2016-12-21T15:41:28.267 回答