Hi,
I’m getting a class name as string via params[:class_name]. How can I
access the class?
E.g.
params[:class_name] => “Post”
and then something like
params[:class_name].to_class.find(:first)
Why I want to to this? I want to create a generic commenting component
with model controller and view (partials) that I can use to comment any
other instance.
For now each class that can be commented (here: Article besides many
others) needs rather the same action code:
class ArticleController < ApplicationController
def comment
@commentable = Article.find(params[:id]) # commentable
@comment = Comment.new
@comment.user = session[‘user’]
@commentable.comments << @comment
if request.post?
@comment = Comment.new(params[:comment])
if @comment.save
render :partial => “comment/comment_list”
else
render :inline => “<%= user_message_helper ‘comment’ %>”,
:status => 500
end
end
end
end
I would like to have this action only once in the CommentController,
somehow like this:
class CommentController < ApplicationController
def comment
class_name = params[:class_name]
@commentable = class_name.to_class.find(params[:id]) # commentable
@comment = Comment.new
@comment.user = session[‘user’]
@commentable.comments << @comment
if request.post?
@comment = Comment.new(params[:comment])
if @comment.save
render :partial => “comment/comment_list”
else
render :inline => “<%= user_message_helper ‘comment’ %>”,
:status => 500
end
end
end
end
I’m sure there is an elegant way to handle this…
starburger wrote:
Hi,
I’m getting a class name as string via params[:class_name]. How can I
access the class?
I think what you want is eval
eval(“Ball”).find(:all)
for example will find all balls with a model class Ball. Not that a
class name is case sensitive!!!
Rob N. wrote:
Not that a class name is case sensitive!!!
Should be:
Note that a class name is case sensitive!!!
On 2/1/07, starburger [email protected] wrote:
and then something like
params[:class_name].to_class.find(:first)
Try String#constantize:
params[:class_name].constantize.find(:first)
Why I want to to this? I want to create a generic commenting component
Thanks a lot for your help - you have solved my problem!
Starburger
Michael G. wrote:
On 2/1/07, starburger [email protected] wrote:
and then something like
params[:class_name].to_class.find(:first)
Try String#constantize:
params[:class_name].constantize.find(:first)
Why I want to to this? I want to create a generic commenting component
how bout eval(params[:class_name].capitalize + “.find(:first)”) ?
Stay away from eval.
Use String#constantize or Object#get_const
Jason
On 1-Feb-07, at 2:13 PM, Jason R. wrote:
Starburger
Jason, Why stay away from eval?
I’m currently using eval to dynamically build a restful url_helper
reference. Is this also a bad case of using eval fro the same reason/?
ala: eval(“change_state_#{the_model.class.name.downcase}_url(#
{the_model.id})”)
(sorry to hijack - hopefully this adds to the discussion!)
Cheers,
Jodi
General Partner
The nNovation Group inc.
www.nnovation.ca/blog

On Feb 1, 2007, at 11:28 AM, Jodi S. wrote:
{the_model.id})")
Jodi-
The reason to stay away from eval is because you want to avoid
evaling anything user generated. The OP is trying to make a class
from an item in the params object. DANGER!! look here:
how bout eval(params[:class_name].capitalize + “.find(:first)”) ?
Now anyone can try to enter all kinds of things in the params
[:class_name] form field. And it will get evaled without any checking
on the server. Bad!
If you can avoid eval please do so at all costs. class_Eval or
instance_eval with blocks instead of strings are better. But in your
example:
eval(“change_state_#{the_model.class.name.downcase}_url(#
{the_model.id})”)
should be written like this:
send(“change_state_#{the_model.class.name.downcase}_url”, “#
{the_model.id}”)
Cheers-
– Ezra Z.
– Lead Rails Evangelist
– [email protected]
– Engine Y., Serious Rails Hosting
– (866) 518-YARD (9273)
On Thursday 01 February 2007 20:28, Jodi S. wrote:
Why stay away from eval?
class SomethingsController < ApplicationController
def tricky
…
eval(params[:my_param])
…
end
end
Then consider what a request like this might do to your server
http://example.com/trickies/tricky?my_param=system("rm%20-rf%20%2F")
Michael
–
Michael S.
mailto:[email protected]
http://www.schuerig.de/michael/
eval(“change_state_#{the_model.class.name.downcase}_url(#
{the_model.id})”)
should be written like this:
send(“change_state_#{the_model.class.name.downcase}_url”, “#
{the_model.id}”)
Hey Ezra -
the send didn’t succeed as :
undefined method `change_state_project_url(:id => 85, :event =>
‘change_project_info’)’ for #<#Class:0x345af20:0x345aef8>
note: this code is running inside application_helper - not sure what
self is inside a helper, but it doesn’t know about rest url helpers.
Do you know what object ‘owns’ these methods? I gather they are Class
methods.
thanx.
Jodi
On 1-Feb-07, at 3:48 PM, Ezra Z. wrote:
Jason
I’m currently using eval to dynamically build a restful url_helper
General Partner
evaling anything user generated. The OP is trying to make a class
instance_eval with blocks instead of strings are better. But in your
Cheers-
– Ezra Z.
– Lead Rails Evangelist
– [email protected]
– Engine Y., Serious Rails Hosting
– (866) 518-YARD (9273)
Thanx Ezra and Michael.
I understood that Send limitted the scope(object calls) of damage
that can be cause by eval - and a object.send("#{params[:command]) is
dangerous enough. Whereby Eval’s scope isn’t limited.
In my particular case the_model is instantiate by the controller
action - so eval would likely be as ‘safe’ as send (?).
My questions was questioning what additional protection that send
provides - is there any protection provided above and beyond the
localization of the class executing the arbritary code?
I think my learning here is that regardless of means(send, eval,
etc), that additionally checking should be done on the methods being
called - limiting the scope of the methods that can be called (I’ve
recently used acts_as_state_machine to limit sends based upon model
state and other guards - this provides funnel that sends must qualify
before running - and still give me the benefit of a measure of dynamism.
ala:
instance.send("#{params[:command]}") if
Class.legitimate_commands.include?(params[:command])
thanks for teaching this ruby-nuby.
Jodi
As everybody has said, avoid eval - use const_get to retrieve a
constant. If you want a class from a string, here’s a simple
implementation:
class String
def to_class
Object.const_get(self)
end
end