records = filters.inject(Idea.published) { |model, name| model.send(name) }.all
First bonus feature is that it knows about all your named scopes, you don’t have to specify them in the controller (business logic in your controller = wrong).
Another bonus feature — multiple filters can be given:
GET /resource?filter=foo&filter=bar
Third bonus feature is that we didn’t need to extend the language with a method that doesn’t do absolutely anything.
(Even tap does something and is incredibly useful.)
I'll admit mine was a bad example. However, the most common (only?)
use case I could see for it is in fact with #send.
Your idea for filtering is great, by the way.
Instead of send you can use instance_eval. Where you'd do something like
obj.send(x? ? :self : :other) you can do obj.instance_eval { x? ? self : other }
I won't comment on your use case, others have already done that.
However. I think naming the method self is potentially confusing,
since self is a keyword which means the receiver of the current
message.
class Foo
def m(arg)
arg.self
end
end
I'd have to think about what self meant anytime I read that.
Smalltalk has a similar method, which is usually used to end a cascade
of message sends (something which ruby doesn't have).
pt = Point.new x:1; y:2; yourself
A rather concocted example, but the point is that the yourself method
returns the receiver, and is IMHO a much better method name.
By way of explanation, a semicolon after a message invocation
indicates that the subsequent message is sent to the receiver of the
preceding message, instead of the result of that mesage. so the above
would be equivalent to:
(somehow managed to forget to hit send on this one yesterday. sigh.)
Smalltalk has a method Object#yourself which does just that. The most common use case is with cascaded message sends, but Ruby doesn't have those. I've wanted #yourself in Ruby now and then too. Since Matz was very familiar with Smalltalk when he created Ruby I assume he didn't think it was necessary, but it's one of the questions I always want to ask him but forget to when I get the chance.
if @admins_only@users.select(&:admin?).sort
else
@users.sort
end
or even
@users = @users.select(&:admin?) if @admins_only@users.sort
I think that is infinitely easier to read and understand (it took me a
while to figure out what the hell your code was doing). Just because
you *can* make everything into a one-liner in Ruby, doesn't mean you
*should*.
Also from the naming of the variables it sounds like you are doing
this in the controller, that's the wrong place to do this sort of
thing, imho. Put it in the model instead!
@users.readable_by(@user)
This clearly communicates what you are trying to achieve.
Never mind that example, I made it up just to illustrate the issue
which
was that the short-circuiting had to happen in the middle of long
method
chain and I didn't want to introduce local variable just for this
optional
filtering step:
SomeModel.some_scope.all.
group_by(&:user).<<optional filtering here >>.
map { ... }.sort_by(&:second).reverse.map(&:first)
Though I must admit this is hardcore and happened to my only once or
twice
As for "track record of getting a language extension into
ActiveSupport
if it's not being used inside the framework", here it is:
I wasn't talking about that specific code sample either. Long chaining
of methods is an anti-pattern and we shouldn't be encouraging it. Put
it in the model and decompose it.