是否有更短的方法来执行以下操作(
@user.employees.map { |e| { id: e.id, name: e.name } }
# => [{ id: 1, name: 'Pete' }, { id: 2, name: 'Fred' }]
User
has_many
雇员。这两个类都继承自ActiveRecord::Base
.
我不喜欢上面的两件事
- 它在映射之前将员工加载到内存中,
- 它很冗长(我猜是主观的)。
有没有更好的办法?
是否有更短的方法来执行以下操作(
@user.employees.map { |e| { id: e.id, name: e.name } }
# => [{ id: 1, name: 'Pete' }, { id: 2, name: 'Fred' }]
User
has_many
雇员。这两个类都继承自ActiveRecord::Base
.
我不喜欢上面的两件事
有没有更好的办法?
更新:
请参阅@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
在 ActiveRecord >= 4 pluck接受多个参数,所以这个例子会变成:
@user.employees.pluck(:id, :name)
如果你被 Rails 3 卡住了,你可以添加这个 .pluck_all
扩展: http: //meltingice.net/2013/06/11/pluck-multiple-columns-rails/
另一种选择是:
@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
添加这个猴子补丁,它在 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
就制作与 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
站在巨人和所有人的肩膀上
pluck_all
在我从 Rails 3.2 升级到 Rails 4 之前,该方法运行良好。
这是一个 gem pluck_all来解决这个问题,pluck_all
不仅在 Rails 3 中,而且在 Rails 4 和 Rails 5 中都支持方法。希望这对那些打算升级 rails 版本的人有所帮助。