Reputation: 23347
In my Rails application I need a class that wraps an ActiveRecord object and disable all its setters. Other methods should be delegated to inner object.
Example:
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
Is there any convenient way to do it besides method_missing
?
Upvotes: 0
Views: 1378
Reputation: 114268
If you just want to prevent updates to the database you can use readonly!
:
person = Person.new(name: "John", age: 12)
person.readonly!
person.age = 123 #=> works
person.save #=> raises ActiveRecord::ReadOnlyRecord
Or you could freeze
the record:
person = Person.new(name: "John", age: 12)
person.freeze
person.age = 123 #=> raises RuntimeError: can't modify frozen Hash
Upvotes: 1
Reputation: 5015
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
Usage
p = Person.first
wrapper = Wrapper.create(p)
wrapper.adult? # => false
wrapper.age = 123 #method not defined
Probably not as convenient as method_missing but it works
[EDIT]
This way means that if the wrapped object does not have some attributes set, then getters will not be created in the wrapping class, if you swap the line
ar_model.attributes.each do |k, v|
for this one
ar_model.class.column_names.each do |k|
then a getter will be created for each column whether the wrapped object has the corresponding attribute set or not
Upvotes: 0