0

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

例子:

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吗?

4

2 回答 2

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
于 2013-10-09T15:24:26.547 回答
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

于 2013-10-09T14:08:07.397 回答