我有以下课程:
class Profile < ActiveRecord::Base
serialize :data
end
配置文件有一个包含序列化哈希的列data
。我想在这个哈希中定义访问器,以便我可以执行profile.name
而不是profile.data['name']
。这可能在Rails中吗?
答案 0 :(得分:1)
class Profile < ActiveRecord::Base
serialize :data # always a hash or nil
def name
data[:name] if data
end
end
答案 1 :(得分:1)
简单明了的方法:
class Profile < ActiveRecord::Base
serialize :data
def name
self.data['name']
end
def some_other_attribute
self.data['some_other_attribute']
end
end
如果您要访问的数据哈希中有许多属性,您可以看到如何快速变得麻烦。
所以这是一种更加动态的方法,它可以用于您想要在data
内访问的任何此类顶级属性:
class Profile < ActiveRecord::Base
serialize :data
def method_missing(attribute, *args, &block)
return super unless self.data.key? attribute
self.data.fetch(attribute)
end
# good practice to extend respond_to? when using method_missing
def respond_to?(attribute, include_private = false)
super || self.data.key?(attribute)
end
end
使用后一种方法,您只需定义method_missing
,然后调用@profile
上data
内关键字的任何属性。因此,调用@profile.name
将通过method_missing
并从self.data['name']
获取值。这适用于self.data
中存在的任何键。希望有所帮助。
进一步阅读:
http://www.trottercashion.com/2011/02/08/rubys-define_method-method_missing-and-instance_eval.html
http://technicalpickles.com/posts/using-method_missing-and-respond_to-to-create-dynamic-methods/
答案 2 :(得分:1)
我要回答我自己的问题。它看起来像我想要的ActiveRecord :: Store:
http://api.rubyonrails.org/classes/ActiveRecord/Store.html
所以我的班级将成为:
class Profile < ActiveRecord::Base
store :data, accessors: [:name], coder: JSON
end
我确信其他人的解决方案都运行得很好,但这很干净。
答案 3 :(得分:0)
class Profile < ActiveRecord::Base
serialize :data # always a hash or nil
["name", "attr2", "attr3"].each do |method|
define_method(method) do
data[method.to_sym] if data
end
end
end
答案 4 :(得分:0)
Ruby非常灵活,您的模型只是一个Ruby类。定义所需的“访问者”方法和所需的输出。
class Profile < ActiveRecord::Base
serialize :data
def name
data['name'] if data
end
end
但是,这种方法会导致大量重复的代码。 Ruby的元编程功能可以帮助您解决这个问题。
如果每个配置文件包含相同的数据结构,您可以使用define_method
[:name, :age, :location, :email].each do |method|
define_method method do
data[method] if data
end
end
如果个人资料包含唯一信息,您可以使用method_missing
尝试查看哈希值。
def method_missing(method, *args, &block)
if data && data.has_key?(method)
data[method]
else
super
end
end