views:

161

answers:

2

I have created a Model class where I define methods based on a method (attribute) called in User (which inherits from Model). The problem is that I cannot override the method defined by define_method, and call super to pass to the defined method. I guess this is because the defined method is added to User itself, and not to the Model, so it actually has no method in the superclass (i.e. Model).

The reason I want to do this is because most attributes should be saved to the database directly, while some attributes, like password, needs some additional processing.

class Model
  def self.attribute(name)
    define_method(name) do
      self
    end
  end  
end

class User < Model
  attribute :password
end

class User2 < Model
  attribute :password

  def password
    super
  end
end

@user = User.new
puts @user.password # => <User:0x00000100845540>

@user2 = User2.new
puts @user2.password
# define_super.rb:17:in `password': super: no superclass method 
# `password' for #<User2:0x00000100845578> (NoMethodError)
# from define_super.rb:25:in `<main>'

Is there any way I could change the code to get this working? I need a way to override dynamically created methods.

+3  A: 

Define the method on the superclass:

class Model
  def self.attribute(name)
    superclass.send :define_method, name do
      self
    end
  end  
end
mtyaka
Thanks. That was just what I needed.
Kim Joar
+1  A: 

The way Rails deals with this is that there are multiple ways to get attributes. One of these is (by convention) never overridden so it can be used in your defined methods:

# This method is never overridden, but also rarely used as a public method
def[](key)
  # Returns value of `key` attribute
end

# This is the effective default implementation of an attribute
def att1
  self[:att1]
end

# This shows how you can have custom logic but still access the underlying value
def att2
  self[:att2] unless self[:att2].empty?
end
Gareth