Can I define_method in rails models?

My rails model has code that is attempting to define_method(method_name) inside the model.

I keep getting:

NoMethodError: undefined method `define_method'

What am I doing wrong? Am I doing this in the wrong place. I need this method attached to this model. Where else can I define this method?

EDIT: For those asking to see the code:

for field in rdev_fields
  next if self.attributes.include?(field)
  count = count + 1
  rdev_hash[field.to_sym] = self.attributes["attribute#{count}"]
  if !self.respond_to?(field) then
    define_method("#{field}") do
      self.send("attribute#{count}".to_sym)
    end
  end
end

Answers


There's nothing magical or about a rails model, it's just a normal class with a bunch of pre-existing methods,

So, the question is "can I define_method in a class"?

Part 1: Yes you can.

The important distinction is than you can define method in a class not in an instance method

For example:

class Cow
  define_method "speak" do
    "MOOOO"
  end
end

Cow.new.speak
=> "MOOOO"

This should work fine. Note you're defining it on the class Cow, so any other Cows that you already have will automatically get that method added.

Part 2: What do you do if you want to define a method from within an instance method?

You can't define methods from an instance method, so you have to grab the class, and use that to define the method. Like this:

class Cow
  def add_speak
    self.class.send(:define_method, :speak) do
      "MOOOO added"
    end
  end
end

Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c48530>

Cow.new.add_speak
Cow.new.speak
=> "MOOOO added"

Problem solved. Astute readers will note that in this example I'm using send(:define_method) - this is needed because define_method is private, and private methods are only accessible to the thing they're in. In this case, define_method is in the class, we are in the instance, so we can't directly access it.

As above though, we're adding the method directly to the class, so all other Cows which already exist will automatically also get the speak method added.

Part 3: What do you do if you want to define a method for only 1 object, not all objects of that class?

Example:

class Cow
  def add_speak_just_me
    class << self
      define_method "speak" do
        "MOOOO added for just me"
      end
    end
  end
end

Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c72b78>

c = Cow.new
c.add_speak_just_me
c.speak
=> "MOOOO added for just me" # it works, hooray

Cow.new.speak # this new cow doesn't have the method, it hasn't been automatically added
NoMethodError: undefined method `speak' for #<Cow:0xb7c65b1c>

How does this work? Down the rabbithole you go!

Read this: http://dannytatom.me/metaid/ and good luck. It helps when you realise that 'adding a method' to an instance isn't actually adding it to the instance at all :-)


Need Your Help

JPA concurrent updates on tree nodes lead to transaction deadlocks

java spring hibernate jpa tree

I support a real world java application (web service) which provides some sort of file system to it's clients. All the metadata of the individual file system trees is kept in the database. Now when...

How to make the cursor in a JTextField span multiple rows in FlowLayout?

java swing jtextfield flowlayout

How can I make the cursor start at the top left of the JTextField? The text just stays centered when I adjust the height with .setPreferredSize(). Here is the code for the fields and buttons. pu...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.