Existe-t-il un moyen plus court de procéder comme suit (
@user.employees.map { |e| { id: e.id, name: e.name } }
# => [{ id: 1, name: 'Pete' }, { id: 2, name: 'Fred' }]
User
has_many
des employés. Les deux classes héritent de ActiveRecord::Base
.
Deux choses que je n'aime pas dans ce qui précède
Y a-t-il une meilleure façon?
MISE À JOUR:
voir la solution de @ jamesharker: depuis ActiveRecord> = 4, pluck
accepte plusieurs arguments:
@user.employees.pluck(:id, :name)
RÉPONSE PRÉCÉDENTE:
pour une seule colonne en Rails> = 3.2, vous pouvez faire:
@user.employees.pluck(:name)
... mais comme vous devez saisir deux attributs, vous pouvez le faire:
@user.employees.select([:id, :name]).map {|e| {id: e.id, name: e.name} }
# or map &:attributes, maybe
si vous vraiment avez besoin d'une opération de niveau inférieur, regardez juste le source de #pluck , qui utilise select_all
Dans ActiveRecord> = 4 pluck accepte plusieurs arguments donc cet exemple deviendrait:
@user.employees.pluck(:id, :name)
Si vous êtes coincé avec Rails 3 vous pouvez ajouter this.pluck_all
extension: http://meltingice.net/2013/06/11/pluck-multiple-columns-Rails/
En termes de création d'une méthode Rails 3 qui se comporte de la même manière que la Rails 4 pluck avec plusieurs colonnes. Cela génère un tableau similaire (plutôt qu'une clé hachée) Cela devrait vous éviter un peu de peine si vous venez de mettre à niveau et que vous souhaitez nettoyer le code.
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
Debout sur les épaules de géants et de tous
Une autre option consiste à:
@user.employees.select(:id, :name).as_json
#=> [{"id" => 1, "name" => "Pete"}, {"id" => 2, "name" => "Fred"}]
Je peux imaginer que vous préférez avoir des clés symbolisées. Si tel est le cas, utilisez le #symbolize_keys
méthode.
@user.employees.select(:id, :name).as_json.map(&:symbolize_keys)
#=> [{id: 1, name: "Pete"}, {id: 2, name: "Fred"}]
Voir: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
Ajoutez ce patch de singe qui fournit la fonctionnalité de saisie de plusieurs colonnes dans 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
Renommez la méthode de pluck
en pluck_all
si vous ne souhaitez pas remplacer la fonctionnalité d'origine pluck
Le pluck_all
la méthode a bien fonctionné jusqu'à ce que je passe de Rails 3.2 à Rails 4.
Voici un joyau pluck_all pour résoudre ce problème, ce qui rend pluck_all
prise en charge de la méthode non seulement dans Rails 3 mais dans Rails 4 et Rails 5. J'espère que cela aidera ceux qui vont mettre à niveau Rails version.