Skip to content

Instantly share code, notes, and snippets.

@spastorino
Created September 5, 2010 22:13
Show Gist options
  • Save spastorino/566374 to your computer and use it in GitHub Desktop.
Save spastorino/566374 to your computer and use it in GitHub Desktop.
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index c3a34ae..14f166b 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -887,7 +887,7 @@ module ActiveRecord #:nodoc:
def scoped_methods #:nodoc:
key = :"#{self}_scoped_methods"
- Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
+ Thread.current[key] = Thread.current[key].presence || []
end
def before_remove_const #:nodoc:
@@ -1412,7 +1412,7 @@ MSG
ensure_proper_type
- if scope = self.class.send(:current_scoped_methods)
+ if scope = self.class.send(:current_scoped_methods) || self.class.send(:default_scoping).dup.last
create_with = scope.scope_for_create
create_with.each { |att,value| self.send("#{att}=", value) } if create_with
end
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index 3de4c40..a6b198c 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -29,7 +29,9 @@ module ActiveRecord
if options
scoped.apply_finder_options(options)
else
- current_scoped_methods ? relation.merge(current_scoped_methods) : relation.clone
+ result = current_scoped_methods ? relation.merge(current_scoped_methods) : relation.clone
+ result = default_scoping.dup.last.override(result) unless default_scoping.empty?
+ result
end
end
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index a6cf59f..dc7367d 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -61,6 +61,54 @@ module ActiveRecord
alias :& :merge
+ def override(r)
+ merged_relation = clone
+ return merged_relation unless r
+
+ Relation::ASSOCIATION_METHODS.each do |method|
+ value = r.send(:"#{method}_values")
+
+ unless value.empty?
+ if method == :includes
+ merged_relation = merged_relation.includes(value)
+ else
+ merged_relation.send(:"#{method}_values=", value)
+ end
+ end
+ end
+
+ (Relation::MULTI_VALUE_METHODS - [:joins, :where]).each do |method|
+ value = r.send(:"#{method}_values")
+ merged_relation.send(:"#{method}_values=", value) if value.present?
+ end
+
+ merged_relation = merged_relation.joins(r.joins_values)
+
+ merged_wheres = @where_values
+
+ r.where_values.each do |w|
+ if w.respond_to?(:operator) && w.operator == :==
+ merged_wheres = merged_wheres.reject {|p| p.respond_to?(:operator) && p.operator == :== && p.operand1.name == w.operand1.name }
+ end
+
+ merged_wheres += [w]
+ end
+
+ merged_relation.where_values = merged_wheres
+
+ Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
+ value = r.send(:"#{method}_value")
+ merged_relation.send(:"#{method}_value=", value) unless value.nil?
+ end
+
+ merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
+
+ # Apply scope extension modules
+ merged_relation.send :apply_modules, r.extensions
+
+ merged_relation
+ end
+
def except(*skips)
result = self.class.new(@klass, table)
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index f538d2a..f350e4f 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -396,6 +396,12 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert not_expected.id != received.id
end
+ def test_named_scope_overwrites_default_with_method_syntax
+ expected = Developer.order('name DESC').collect { |dev| dev.name }
+ received = DeveloperOrderedBySalaryWithMethodSyntax.by_name.collect { |dev| dev.name }
+ assert_equal expected, received
+ end
+
def test_nested_exclusive_scope
expected = Developer.find(:all, :limit => 100).collect { |dev| dev.salary }
received = DeveloperOrderedBySalary.send(:with_exclusive_scope, :find => { :limit => 100 }) do
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 947583a..331318f 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -97,6 +97,12 @@ class DeveloperOrderedBySalary < ActiveRecord::Base
end
end
+class DeveloperOrderedBySalaryWithMethodSyntax < ActiveRecord::Base
+ self.table_name = 'developers'
+ default_scope order('salary DESC')
+ scope :by_name, order('name DESC')
+end
+
class DeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
default_scope :conditions => "name = 'David'"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment