1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Prevent scope named same as a ActiveRecord::Relation instance method.

Due to inconsistent behavior when chaining scopes and one scope named after a Relation method

Validation code added in 2 places:

- scope, to prevent problematic scope names.
- enum, cause it tries to auto define scope.
This commit is contained in:
Chen Kinnrot 2017-11-18 21:22:00 +02:00
parent f2b6406066
commit 6552ce0361
5 changed files with 48 additions and 0 deletions

View file

@ -1,3 +1,9 @@
* Don't allow scopes to be defined which conflict with instance methods on `Relation`.
Fixes #31120.
*kinnrot*
## Rails 5.2.0.beta1 (November 27, 2017) ##
* Add new error class `QueryCanceled` which will be raised

View file

@ -221,6 +221,8 @@ module ActiveRecord
def detect_enum_conflict!(enum_name, method_name, klass_method = false)
if klass_method && dangerous_class_method?(method_name)
raise_conflict_error(enum_name, method_name, type: "class")
elsif klass_method && method_defined_within?(method_name, Relation)
raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
elsif !klass_method && dangerous_attribute_method?(method_name)
raise_conflict_error(enum_name, method_name)
elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)

View file

@ -171,6 +171,12 @@ module ActiveRecord
"a class method with the same name."
end
if method_defined_within?(name, Relation)
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
"on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
"an instance method with the same name."
end
valid_scope_name?(name)
extension = Module.new(&block) if block

View file

@ -308,6 +308,24 @@ class EnumTest < ActiveRecord::TestCase
end
end
test "reserved enum values for relation" do
relation_method_samples = [
:records,
:to_ary,
:scope_for_create
]
relation_method_samples.each do |value|
e = assert_raises(ArgumentError, "enum value `#{value}` should not be allowed") do
Class.new(ActiveRecord::Base) do
self.table_name = "books"
enum category: [:other, value]
end
end
assert_match(/You tried to define an enum named .* on the model/, e.message)
end
end
test "overriding enum method should not raise" do
assert_nothing_raised do
Class.new(ActiveRecord::Base) do

View file

@ -151,6 +151,22 @@ class NamedScopingTest < ActiveRecord::TestCase
assert_equal "The scope body needs to be callable.", e.message
end
def test_scopes_name_is_relation_method
conflicts = [
:records,
:to_ary,
:to_sql,
:explain
]
conflicts.each do |name|
e = assert_raises ArgumentError do
Class.new(Post).class_eval { scope name, -> { where(approved: true) } }
end
assert_match(/You tried to define a scope named \"#{name}\" on the model/, e.message)
end
end
def test_active_records_have_scope_named__all__
assert !Topic.all.empty?