diff options
-rw-r--r-- | activerecord/CHANGELOG.md | 20 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation/spawn_methods.rb | 15 | ||||
-rw-r--r-- | activerecord/test/cases/relation_test.rb | 4 |
3 files changed, 37 insertions, 2 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c78e602af7..8356b49bec 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,25 @@ ## Rails 4.0.0 (unreleased) ## +* Allow Relation#merge to take a proc. + + This was requested by DHH to allow creating of one's own custom + association macros. + + For example: + + module Commentable + def has_many_comments(extra) + has_many :comments, -> { where(:foo).merge(extra) } + end + end + + class Post < ActiveRecord::Base + extend Commentable + has_many_comments -> { where(:bar) } + end + + *Jon Leighton* + * Add CollectionProxy#scope This can be used to get a Relation from an association. diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index dcd4c78eb7..5394c1b28b 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -23,6 +23,13 @@ module ActiveRecord # # Returns the intersection of all published posts with the 5 most recently created posts. # # (This is just an example. You'd probably want to do this with a single query!) # + # Procs will be evaluated by merge: + # + # Post.where(published: true).merge(-> { joins(:comments) }) + # # => Post.where(published: true).joins(:comments) + # + # This is mainly intended for sharing common conditions between multiple associations. + # def merge(other) if other.is_a?(Array) to_a & other @@ -35,8 +42,12 @@ module ActiveRecord # Like #merge, but applies changes in place. def merge!(other) - klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger - klass.new(self, other).merge + if !other.is_a?(Relation) && other.respond_to?(:to_proc) + instance_exec(&other) + else + klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger + klass.new(self, other).merge + end end # Removes from the query the condition(s) specified in +skips+. diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 034339e413..5fb54b1ca1 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -247,5 +247,9 @@ module ActiveRecord assert relation.merge!(where: :foo).equal?(relation) assert_equal [:foo], relation.where_values end + + test 'merge with a proc' do + assert_equal [:foo], relation.merge(-> { where(:foo) }).where_values + end end end |