-
Notifications
You must be signed in to change notification settings - Fork 22.2k
Description
Prior to Rails 5 applications were able to define a scope with a method name that happened to match many methods on Enumerable and treat it like any other scope. While attempting to upgrade an older application to Rails 5 I started receiving errors for calls to a legacy group_by scope that accepted a single parameter.
I think this commit introduced the change that triggered the error: b644964
Including the bug report components in case the maintainers want to treat this as a bug. I think it is also reasonable to treat this as an intended change considering that relations already had a few methods from Enumerable explicitly defined on them. If it is intended then I think it should be noted in the docs somewhere (maybe just the 4.2 -> 5.0 upgrade docs).
Steps to reproduce
- Create a scope on Rails 4.2 with a method name that matches a method on
Enumerablebut is not explicitly noted in the Rails guides.
- Use a method like
group_byrather than something likeany?which has been noted in Rails docs for a while
- Construct and execute a query using that scope
- Observe that the scope is executed as expected
- Switch to Rails 5 and follow steps 1 and 2
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
gem "rails", github: "rails/rails"
gem "sqlite3"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
t.string :name
end
create_table :comments, force: true do |t|
t.integer :post_id
end
end
class Post < ActiveRecord::Base
has_many :comments
scope :group_by, ->(value) { group(value) }
end
class Comment < ActiveRecord::Base
belongs_to :post
def self.group_by(value)
group(value)
end
end
class BugTest < Minitest::Test
def test_group_by_with_class_method
assert_nothing_raised(Comment.all.group_by('post_id'))
end
def test_group_by_with_scope
assert_nothing_raised(Post.all.group_by('name'))
end
endExpected behavior
The scope is executed as expected, just as in Rails 4.2
Actual behavior
The scope is never called because the method from Enumerable is found and called first. If the arity of your scope is different from the arity of the method on Enumerable then an error is thrown.
System configuration
Rails version: 5.0.0.1 (although the bug demo script happens to reproduce the behavior against 5.1.0.alpha)
Ruby version: 2.3.1