从ActiveRecord对象中提取两个属性的快捷方式?

时间:2012-12-08 11:36:33

标签: ruby-on-rails ruby ruby-on-rails-3

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

@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. 这是冗长的(主观我猜)。
  3. 有更好的方法吗?

7 个答案:

答案 0 :(得分:43)

<强>更新

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

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

以前的答案:

对于rails&gt; = 3.2中的单个列,您可以执行以下操作:

@user.employees.pluck(:name)

...但是你需要选择两个属性,你可以这样做:

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

如果确实需要更低级别的操作,请查看使用select_all

source of #pluck

答案 1 :(得分:36)

在ActiveRecord&gt; = 4 pluck接受多个参数,因此此示例将变为:

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

答案 2 :(得分:7)

如果您遇到Rails 3,可以添加this .pluck_all分机:http://meltingice.net/2013/06/11/pluck-multiple-columns-rails/

答案 3 :(得分: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

答案 4 :(得分:0)

在制作rails 3方法方面,其行为与Rails 4采用多列相同。这会输出一个类似的数组(而不是散列键值集合)。如果你来升级并想要清理代码,这应该可以节省一些痛苦。

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

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

答案 5 :(得分:0)

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

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

答案 6 :(得分: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