Permalink
Browse files

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
  • Loading branch information...
1 parent c391919 commit bf2df6e7ba495ac4d2264e0e2558c366f217ee5d @jonleighton jonleighton committed Aug 3, 2012
View
@@ -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.
@@ -23,6 +23,13 @@ def spawn #:nodoc:
# # 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 @@ def merge(other)
# 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+.
@@ -247,5 +247,9 @@ def relation
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

0 comments on commit bf2df6e

Please sign in to comment.