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:
parent
f2b6406066
commit
6552ce0361
5 changed files with 48 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
Loading…
Reference in a new issue