Reputation: 43123
So, this is a rails app but really more of a general ruby question:
I have a model with several scopes. For example:
Photo.recent
Photo.popular
Photo.featured
I have a "browse photos" view in my app where I want to be able to pass a single param and let the user specify a scope they want to view, ie:
example.com/photos/browse?view=recent
This gives me params[:view], and I need to attach that as a method call on Photo.
So my first question is, how can you do that kind of thing in Ruby?
Second, this could be a security risk if I can't constrain the input, if I just attach Photo.whatever the user types in the url
then I'm at risk for a hacker saying example.com/photos/browse?view=delete_all
That, obviously, is a bad idea.
So my second question is, how can I create a whitelist or something for what can be called -- or even better setup some kind of method that can accept the param from the URL safely and only return information if the user is requesting a valid named scope.
Lastly, I have some scopes that are only for admins. I have user abilities defined (using CanCan) so I can query current_user.has_role?
to check if a user is authorized for anything, but is there a way to associate permissions with a scope?
Thanks!
Upvotes: 0
Views: 206
Reputation: 18350
TBH, unless you have a lot of these scopes, I would just hardcode them or create a hash mapping the url param values to lambdas
In the event that you do want to do exactly what you said, you could do something like:
whitelist = %w(
recent
popular
featured
)
if whitelist.include? params[:view]
photos = Photo.send params[:view].to_sym
end
See: http://apidock.com/ruby/Object/send
EDIT: Perhaps try this?
if Photo.valid_scope_name? params[:view]
photos = Photo.send params[:view].to_sym
end
It's a protected method, so you might have to use:
if Photo.send :valid_scope_name?, params[:view]
photos = Photo.send params[:view].to_sym
end
http://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/valid_scope_name%3F
Upvotes: 2
Reputation: 26997
To send a method, use the send method :)
Photo.send(params[:view].to_sym)
However, you are 100% correct to assume this (might) be a security concern. Subsequently, you may want to do something like the following:
Photo.send(params[:view].to_sym) if %w(recent popular featured).include?(params[:view])
Upvotes: 1