Подтвердить что ты не робот

Ярлык для выщипывания двух атрибутов из объекта ActiveRecord?

Существует ли более короткий способ сделать следующее (

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

User has_many сотрудников. Оба класса наследуют от ActiveRecord::Base.

Две вещи, которые мне не нравятся выше

  • Он загружает сотрудников в память перед отображением,
  • Это подробный (субъективный, я думаю).

Есть ли лучший способ?

4b9b3361

Ответ 1

UPDATE:

см. решение @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

Ответ 2

В ActiveRecord >= 4 pluck принимает несколько аргументов, чтобы этот пример стал:

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

Ответ 4

Добавьте этот патч обезьяны, который обеспечивает многопользовательскую функцию сложения в 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

Ответ 5

С точки зрения создания метода рельсов 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

Стоя на плечах гигантов и всех

Ответ 6

Метод pluck_all работал хорошо, пока я не перейду с Rails 3.2 на Rails 4.

Вот этот камень pluck_all, чтобы решить эту проблему, сделав поддержку метода pluck_all не только в Rails 3, но и в Rails 4 и Rails 5. Надеюсь, это поможет тем, кто собирается обновить версию rails.

Ответ 7

Другой вариант:

@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