委派所有方法但设置者

时间:2013-10-09 13:54:23

标签: ruby-on-rails ruby delegates

在我的Rails应用程序中,我需要一个包装ActiveRecord对象并禁用其所有setter的类。其他方法应该委托给内部对象。

示例:

class Person < ActiveRecord::Base
  attr_accessible :name, :age
  def adult?
    age >= 18
  end
end

class PersonWrapper
  def initialize(person)
    @person = person
  end
end

person = Person.new(name: "John", age: 12)
wrapper = PersonWrapper.new(Person)

wrapper.age # => 12
wrapper.adult? # => false
wrapper.age = 123 # error

除了method_missing之外,有没有方便的方法呢?

2 个答案:

答案 0 :(得分:1)

如果您只想阻止对数据库的更新,可以使用readonly!

person = Person.new(name: "John", age: 12)
person.readonly!
person.age = 123  #=> works
person.save       #=> raises ActiveRecord::ReadOnlyRecord

或者你可以freeze记录:

person = Person.new(name: "John", age: 12)
person.freeze
person.age = 123  #=> raises RuntimeError: can't modify frozen Hash

答案 1 :(得分:0)

class Wrapper
  def self.create(ar_model)
    klass = Class.new
    ar_model.attributes.each do |k, v|
      klass.send(:define_method, k) { @obj[k] }
    end
    klass.send(:define_method, :initialize) {|obj| @obj = obj}
    klass.new(ar_model)
  end
end

用法

p = Person.first
wrapper = Wrapper.create(p)
wrapper.adult? # => false
wrapper.age = 123 #method not defined

可能不如method_missing方便,但它可以正常工作

[编辑]

这种方式意味着如果包装的对象没有设置某些属性,那么如果你交换行就不会在包装类中创建getter

ar_model.attributes.each do |k, v|

这个

ar_model.class.column_names.each do |k|

然后将为每个列创建一个getter,无论包装对象是否具有相应的属性集