views:

26

answers:

1

I'm not sure if this can even be achieved, but here goes... :)

Lets assume two models, a Page model and a Field model. A Page has_many :fields and the Field model has two attributes: :name, :value

What I want to achieve is in the Page model to dynamically define instance methods for each Field#name returning the Field#value.

So if my page had a field with a name of "foobar", I would dynamically create a method like so:

def foobar
  fields.find_by_name("foobar").value
end

Can this be achieved? If so, please help?

Over to the rubyists...

+1  A: 

You can override method_missing to achieve your goal:

def method_missing(method, *args, &block)
  super
rescue NoMethodError => e
  field = fields.find_by_name(method)
  raise e unless field
  field.value
end

Probably it's better to add prefix or suffix to your dynamic methods, e.g.:

def method_missing(method, *args, &block)
  if method.starts_with?('value_of_')
    name = method.sub('value_of_', '')
    field = fields.find_by_name(method)
    field && field.value
  else
    super
  end
end

And call it like:

page.value_of_foobar
lest
Uh, catch and re-raise, does't look very good. Why not invert the order? Look for field, if exists, return the value, else, call super and continue with the method missing chain. The only drawback I see with method missing is that you couldn't have values named as the already defined methods
Chubas
You can add prefix or suffix to your dynamic methods.Then it wouldn't have such side effect.
lest
One nice pattern you can use with method missing is:- When method missing is called, dynamically add that method to the object being called then call onto that method. From then on, the object has the method, so avoids other calls to method missing. ActiveRecord does this, but you don't typically change columns at runtime, I am guessing you would be changing fields at runtime.
Nigel Thorne
Thank you, that's a great help
aaronrussell