Reputation: 4190
I have a Restriction model that represent a formula
. The field formula
is a string that at runtime is evaluated. This field can't be accessed from outside for security reasons so I'am trying to override the accessors.
class Restriction < ActiveRecord::Base
belongs_to :indicator
RESTRICTION_TYPES = {
less_than: "IND<X",
greater_than: "X<IND",
between: "X<IND && IND<Y"
}
def evaluate(number)
f = formula.gsub("IND", "#{number}")
eval(f)
end
def create_formula(type_name, arg)
if(type_name == :between)
f = RESTRICTION_TYPES[:between].gsub("X", "#{arg[0]}").gsub("Y", "#{arg[1]}")
else
f = RESTRICTION_TYPES[type_name].gsub("X", "#{arg}")
end
formula = f
end
private
def formula= f
write_attribute(:formula, f)
end
def formula
read_attribute(:formula)
end
def [](value)
super[value]
end
def []=(key, value)
super[key] = value
end
end
In rails console:
Loading development environment (Rails 4.0.0)
2.0.0p247 :001 > r = Restriction.new
=> #<Restriction id: nil, formula: nil, indicator_id: nil, created_at: nil, updated_at: nil, state: nil>
2.0.0p247 :002 > r.create_formula(:between, [1,2])
=> "1<IND && IND<2"
2.0.0p247 :003 > r.evaluate 1.5
NoMethodError: undefined method 'gsub' for nil:NilClass
2.0.0p247 :004 > r
=> #<Restriction id: nil, formula: nil>
formula
is not change the value. What am I doing wrong?
PS: You can see that I have also overriden [](value)
and []=(key, value)
. This is due to my previous question
Upvotes: 0
Views: 716
Reputation: 745
Rails internally relies on the hash like access methods for reading and writing attributes. By making them private you wanted to restrict the access of [] and []= to from within the object only. But you destroyed the method, because you are using super the wrong way. When calling super
you are not getting the super object of this class, but the super method, the current method overrides. Thus change it like this and it should work:
def [](value)
super(value)
end
def []=(key, value)
super(key, value)
end
P.S.: Overriding a method for declaring it private is overkill in Ruby. You can simply declare it private with
private :[], []=
Upvotes: 1