Skip to content

Commit

Permalink
Allow ActiveRecord::QueryMethods#pluck to accept hash args with sym…
Browse files Browse the repository at this point in the history
…bol & string values
  • Loading branch information
joshuay03 committed Apr 27, 2024
1 parent f04c59b commit a683d64
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 9 deletions.
9 changes: 9 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
* Allow `ActiveRecord::Base#pluck` to accept hash arguments with symbol and string values.

```ruby
Post.joins(:comments).pluck(:id, comments: :id)
Post.joins(:comments).pluck("id", "comments" => "id")
```

*Joshua Young*

* Strict loading using `:n_plus_one_only` does not eagerly load child associations.

With this change, child associations are no longer eagerly loaded, to
Expand Down
6 changes: 5 additions & 1 deletion activerecord/lib/active_record/relation/calculations.rb
Expand Up @@ -275,10 +275,14 @@ def calculate(operation, column_name)
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
# # => [2, 3]
#
# Comment.joins(:person).pluck(:id, person: [:id])
# Comment.joins(:person).pluck(:id, person: :id)
# # SELECT comments.id, people.id FROM comments INNER JOIN people on comments.person_id = people.id
# # => [[1, 2], [2, 2]]
#
# Comment.joins(:person).pluck(:id, person: [:id, :name])
# # SELECT comments.id, people.id, people.name FROM comments INNER JOIN people on comments.person_id = people.id
# # => [[1, 2, 'David'], [2, 2, 'David']]
#
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
# # SELECT DATEDIFF(updated_at, created_at) FROM people
# # => ['0', '27761', '173']
Expand Down
24 changes: 16 additions & 8 deletions activerecord/lib/active_record/relation/query_methods.rb
Expand Up @@ -2110,14 +2110,14 @@ def check_if_method_has_arguments!(method_name, args, message = nil)
def process_select_args(fields)
fields.flat_map do |field|
if field.is_a?(Hash)
arel_columns_from_hash(field)
arel_columns_from_hash(field, for_select: true)
else
field
end
end
end

def arel_columns_from_hash(fields)
def arel_columns_from_hash(fields, for_select: false)
fields.flat_map do |key, columns_aliases|
case columns_aliases
when Hash
Expand All @@ -2126,22 +2126,30 @@ def arel_columns_from_hash(fields)
references = PredicateBuilder.references({ key.to_s => fields[key] })
self.references_values |= references unless references.empty?
end
arel_column("#{key}.#{column}") do
predicate_builder.resolve_arel_attribute(key.to_s, column)
end.as(column_alias.to_s)
build_arel_attribute(key.to_s, column.to_s).as(column_alias.to_s)
end
when Array
columns_aliases.map do |column|
arel_column("#{key}.#{column}", &:itself)
end
when String, Symbol
arel_column(key.to_s) do
predicate_builder.resolve_arel_attribute(klass.table_name, key.to_s)
end.as(columns_aliases.to_s)
if for_select
arel_column(key.to_s) do
predicate_builder.resolve_arel_attribute(klass.table_name, key.to_s)
end.as(columns_aliases.to_s)
else
build_arel_attribute(key.to_s, columns_aliases.to_s)
end
end
end
end

def build_arel_attribute(table_name, column_name)
arel_column("#{table_name}.#{column_name}") do
predicate_builder.resolve_arel_attribute(table_name.to_s, column_name)
end
end

STRUCTURAL_VALUE_METHODS = (
Relation::VALUE_METHODS -
[:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
Expand Down
5 changes: 5 additions & 0 deletions activerecord/test/cases/calculations_test.rb
Expand Up @@ -958,7 +958,10 @@ def test_pluck_with_hash_argument
[2, "The Second Topic of the day"],
[3, "The Third Topic of the day"]
]
assert_equal expected, Topic.order(:id).limit(3).pluck(:id, topics: :title)
assert_equal expected, Topic.order(:id).limit(3).pluck("id", "topics" => "title")
assert_equal expected, Topic.order(:id).limit(3).pluck(:id, topics: [:title])
assert_equal expected, Topic.order(:id).limit(3).pluck("id", "topics" => ["title"])
end

def test_pluck_with_hash_argument_with_multiple_tables
Expand All @@ -967,6 +970,8 @@ def test_pluck_with_hash_argument_with_multiple_tables
[1, 2, "Thank you again for the welcome"],
[2, 3, "Don't think too hard"]
]
assert_equal expected, Post.joins(:comments).order(posts: { id: :asc }, comments: { id: :asc }).limit(3).pluck(:id, comments: [:id, :body])
assert_equal expected, Post.joins(:comments).order(posts: { id: :asc }, comments: { id: :asc }).limit(3).pluck(posts: :id, comments: [:id, :body])
assert_equal expected, Post.joins(:comments).order(posts: { id: :asc }, comments: { id: :asc }).limit(3).pluck(posts: [:id], comments: [:id, :body])
end

Expand Down

0 comments on commit a683d64

Please sign in to comment.