[ActiveRecord] scope for collection associations

IIRC with Rails 4 associations introduce their methods via a module, which means you can super to them, so why not:

class Post

has_many :comments

def comments(*)

super.visible

end

end

I’m not too keen on having moar DSL when defining a simple method suffices. It also gives you more flexibility to call whatever on the association.

For example, your suggestion to avoid an Array of scopes is to define an extra scope / singleton method on Comment for the sole purpose of having something you can call here. But then you’re defining a method on Comment that you only use from Post, which is weird (and potentially confusing—later one someone might change the scope passed to the association, but might not know that the scope definition on Comment is no longer used, so you end up with dead code).

With this approach you can simply call whatever you want on the method overriding the association, instead of having to do extra work just for the sake of having a DSL.

Cheers,

-foca

foca, in your example, I’d use Post.find(1).comments to get only the visible comments. How would I be able to get ALL the comments, including the hidden ones? I’m thinking of passing a parameter to the comments method.

class Post

has_many :comments

def comments(show_hidden = false)

show_hidden ? super : super.visible

end

end

Is this the right way?

The problem with that is that you’re overloading the meaning of association(flag). When passing a boolean to an association, you are telling it to force-reload the association (if true). If I read in the code “post.comments(true)” I will always think you’re trying to force-reload the association, which would be weird :slight_smile:

If you want to have both versions of the association (with and without the scope), I would just define a different method (visible_comments).

There’s also a subtle bug with your code: The version of super without parentheses will invoke the superclass method with the same arguments than the current method, which would pass the boolean flag to the association per-se, which would have weird effects (since you’d force an extra query every time you try to load the visible comments).

You would need to call super() like so:

def comments(show_hidden = false)

show_hidden ? super() : super().visible

end

Cheers,

-foca

Ah-ha! Didn’t think of the super-without-paranthesis bug! Very subtle, good catch!