覆盖Ruby on Rails 4上的属性访问器

时间:2013-08-05 13:23:28

标签: ruby-on-rails ruby-on-rails-4 attr-accessor

我有一个代表formula的限制模型。字段formula是在运行时评估的字符串。出于安全原因,无法从外部访问此字段,因此我试图覆盖访问者。

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

在rails控制台中:

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不会更改该值。我做错了什么?

PS:您可以看到我也覆盖了[](value)[]=(key, value)。这是由于我的previous question

1 个答案:

答案 0 :(得分:1)

Rails内部依赖于类似于哈希的访问方法来读取和写入属性。通过将它们设为私有,您希望仅限制对象内的[]和[] =的访问权限。但是你破坏了这个方法,因为你使用的是超级错误的方法。当调用super时,你没有得到这个类的超级对象,而是超级方法,当前方法会覆盖。因此,改变它,它应该工作:

def [](value)
  super(value)
end

def []=(key, value)
  super(key, value)
end

P.S。:重写一种声明私有的方法在Ruby中是过度的。你可以简单地用

声明它是私有的
private :[], []=