peter
peter

Reputation: 42207

pass class as parameter in Ruby

My current sinatra router looks like this but multiple stores are on the way so i would like to replace this case with one line,

get_or_post "/list.json" do
  case
    when params[:store]=='storeVakanties' then return jsonp(get_data_for(Vakantie))
    when params[:store]=='storeDeelnemers' then return jsonp(get_data_for(Deelnemer))
    when params[:store]=='storeJobstudenten' then return jsonp(get_data_for(Jobstudent))
  end
end

if i rename my ExtJs store to the name of the activerecord class i could do something like

get_or_post "/list.json" do
  jsonp(get_data_for(params[:store])) #eg params[:store]='Vakantie'
end

but i need to pass a class, not a string.. any suggestions ?

Upvotes: 1

Views: 831

Answers (4)

Stefan
Stefan

Reputation: 114268

If you want to restrict the available classes, something like this would work:

params = { store: "Vakantie" }

[Vakantie, Deelnemer, Jobstudent].find { |c| c.to_s == params[:store] }
#=> Vakantie

I would probably just write a helper method and map the classes explicitly:

helpers do
  def store(name)
    case name
    when 'storeVakanties' then Vakantie
    when 'storeDeelnemers' then Deelnemer
    when 'storeJobstudenten' then Jobstudent
    end
  end
end

get_or_post "/list.json" do
  jsonp(get_data_for(store(params[:store])))
end

Upvotes: 1

peter
peter

Reputation: 42207

I found a solution myself using ActiveSupport's constantize

jsonp(get_data_for(params[:store].constantize))

In my case security isn't an issue but i like the solution from Stefan the best so i give him the credits.

Upvotes: 0

BroiSatse
BroiSatse

Reputation: 44725

In the simplest case (no namespaces) you can use:

Object.const_get(params[:store])

If you need to get namespaced constant, you can do

params[:store].split('::').inject(Object) {|klass, name| klass.const_get(name) }

For more advanced implementation have a look at the source of constantize method from ActiveSupport's Inflector: http://apidock.com/rails/v4.0.2/ActiveSupport/Inflector/constantize

Upvotes: 2

Buck Doyle
Buck Doyle

Reputation: 6397

You could use eval:

get_or_post "/list.json" do
  jsonp(get_data_for(eval(params[:store])))
end

If you’re horrified by that, you could use const_get:

Kernel.const_get(params[:store])

You’ll need to perform some validation, though, because it’s dangerous to allow user input to select any defined class.

Upvotes: 0

Related Questions