views:

192

answers:

5

In my posts model, I have a named scope:

named_scope :random, :order => "Random()"

I'd like to give users the ability to get posts in a random order by sending a GET request with params[:scope] = 'random'.

Short of eval("Post.#{params[:scope]}"), how can I do this?

+1  A: 

I would stay away from eval since you're dealing with data that comes from the user. Maybe just use a simple case statement? This way you'll be able to validate what the data they're giving you.

Mark A. Nicolosi
+2  A: 

I would suggest my very awesome acts_as_filter plugin designed for user-driven filtering of results via named_scopes.

http://github.com/tobyhede/acts_as_filter/tree/master

Eval is fine to use - but make sure you validate against accepted/expected values (I often just plug some values into an array and test accepted_values.include?(parameter))

Toby Hede
+2  A: 

eval is a pretty bad idea. However, #send is perfect for this - it's inherently safer, and faster than eval (as I understand it).

Product.send(params[:scope])

That should do it :)

Brian Hogan
A: 

For the example you give, I'd be explicit, and chain scopes together to build the query you want:

scope = Post
scope = scope.random if params[:scope] == 'random'
@posts = scope.find(:all, ...) # or paginate or whatever you need to do

If params[:scope] isn't 'random', this is the same as calling Post.find(), otherwise it's doing Post.random.find()

From one of the other answers, it looks like find_by_filter would do pretty much the same thing for you.

Using this pattern, you can also combine multiple scopes into the query if you needed to support things that weren't mutually exclusive e.g.

scope = scope.only_monsters if params[:just_monsters] == 1    
scope = scope.limit(params[:limit].to_i) unless params[:limit].to_i.zero?

So GETting /posts?scope=random&just_monsters=1&limit=5 will give you:

Post.random.just_monsters.limit(5).find(:all, ...)
Simon
+1  A: 

I know this is an old question, but I came across it in a search. searchlogic is perfect for this.

Ben Johnson