如何在Rails 3.x中提取多个属性?

时间:2017-10-11 19:39:28

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

我有一个像这样的ActiveRecord模型:

class Person < ActiveRecord::Base
  attr_accessible :name
end

并且需要将Person id哈希映射到name s:

{1 => "Paul", 2 => "Aliyah", 3 => ... }

现在,显而易见的方法是

Person.all.collect { |p| [p.id, p.name] }.to_h

但是,我不需要实例化每个Person,我只需要哈希。在Rails 4中,我可以.pluck(:id, :name)而不是collect,但是在3.x中,pluck只接受一个参数。但是我发现这个解决方法是为了得到我想要的而不加载模型:

Person.all.group(:id).minimum(:name)

问题:我会在地狱中燃烧吗?此外,是否有一种更优雅的方式来实现这一点,这种hacky方法有任何缺点,我可能不知道吗?谢谢!

4 个答案:

答案 0 :(得分:3)

以下是对这种情况以及处理它的各种策略的非常好的描述:Plucking Multiple Columns in Rails 3

我建议的解决方案的偏好是制作并包含一个模块:

# multi_pluck.rb
require 'active_support/concern'

module MultiPluck
  extend ActiveSupport::Concern

  included do
    def self.pluck_all(relation, *args)
      connection.select_all(relation.select(args))
    end
  end
end

答案 1 :(得分:1)

class Person < ActiveRecord::Base
  attr_accessible :name

  def self.pluck_id_and_name
     result = connection.select_all(select(:id, :name))
     if result.any?
       # if you are using Ruby 2.1+
       result.to_h
       # Works in 1.9.3+
       Hash[result]
     end
  end
end

由于结果应该是一个数组数组,我们可以使用漂亮的技巧来获取散列,第一个元素作为键,第二个元素作为值:

Hash[ [ [1, "Joe"], [2, "Jill"] ] ] 
# => { 1 => "Joe", 2 => "Jill"}

请参阅:

答案 2 :(得分:0)

为避免加载所有对象,您可以这样做:

hash = Hash.new
ActiveRecord::Base.connection.execute("SELECT id, name FROM persons").each {|person| hash[person['id'].to_s] = person['name'].to_s}

答案 3 :(得分:0)

我的公司之前使用过Plucking Multiple Columns in Rails 3之一的策略。 但是我们无法从Rails 3升级到Rails 4,因为它在Rails 4中不起作用。

我建议使用pluck_all gem,它在Rails 3,4,5中具有较高的测试覆盖率,因此您不必担心将来的升级。