>From the examples in documents, it looks like AR#pluck is mainly for 
retrieving columns from the same table. Like 
Post.pluck(:author_id)

But we can also find some people using pluck for joined tables' columns, 
like 
Post.joins(:author).pluck("author.name", :title)

And normally this works fine, except for cases 
like https://github.com/rails/rails/issues/36042. 

class Post < ActiveRecord::Base
  enum status: {
    a: "a",
    b: "b",
    c: "c"
  }
  has_many :comments
end

class Comment < ActiveRecord::Base
  enum status: {
    red: "red",
    green: "green",
    blue: "blue"
  }
  belongs_to :post
end

class BugTest < Minitest::Test
  def test_association_stuff
    post = Post.create!(status: "a")
    post.comments << Comment.create!(status: "blue", not_enum: "blue")

    expected = [["a", "blue", "blue"]]
    actual = Post.includes(:comments).pluck(:status, "comments.status", 
"comments.not_enum")
    assert_equal expected, actual
  end
end


After digging into the issue, I think plucking joined tables' columns is 
kind of a misuse of pluck. Here's the source code of pluck

    def pluck(*column_names)
      if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - 
@klass.attribute_aliases.keys).empty?
        return records.pluck(*column_names)
      end

      if has_include?(column_names.first)
        relation = apply_join_dependency
        relation.pluck(*column_names)
      else
        klass.disallow_raw_sql!(column_names)
        relation = spawn
        relation.select_values = column_names
        result = skip_query_cache_if_necessary { 
klass.connection.select_all(relation.arel, nil) }
        result.cast_values(klass.attribute_types)
      end
    end


And the cause of the issue above is 

result.cast_values(klass.attribute_types)

Pluck seems assume it'll only be used for the same table, so it uses the 
original class' attribute types to cast column values (in this case, the 
Post's attribute types). Hence when the joined table's columns need 
different casting methods (like different enum definitions), Rails may get 
confused. (For generic types like integer, string that won't be a problem 
though, that's why most people don't have issue). And for our issue 
example, Rails tried to use Post's status type definition to cast Comment's 
status type, and as expected it failed.

So my question is, should we have a full support on this behavior? Which 
means we'd need to be able to cast types for every tables envolved. And 
this won't be a small change since we now need to get all tables' type 
definitions. Or we should consider this as a misuse and not receommending 
using it (or even deprecate it).






-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to rubyonrails-core+unsubscr...@googlegroups.com.
To post to this group, send email to rubyonrails-core@googlegroups.com.
Visit this group at https://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.

Reply via email to