我有下面的类:访问属性里面散列列
class Profile < ActiveRecord::Base
serialize :data
end
档案具有保持序列化哈希单列data
。我想将访问器定义为该散列,以便我可以执行profile.name
而不是profile.data['name']
。这在Rails中可能吗?
我有下面的类:访问属性里面散列列
class Profile < ActiveRecord::Base
serialize :data
end
档案具有保持序列化哈希单列data
。我想将访问器定义为该散列,以便我可以执行profile.name
而不是profile.data['name']
。这在Rails中可能吗?
简单直接的方式:
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/
class Profile < ActiveRecord::Base
serialize :data # always a hash or nil
def name
data[:name] if data
end
end
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
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
我要回答我的问题。它看起来像的ActiveRecord :: Store是什么,我想:
http://api.rubyonrails.org/classes/ActiveRecord/Store.html
所以我的课将成为:
class Profile < ActiveRecord::Base
store :data, accessors: [:name], coder: JSON
end
我敢肯定,每个人的解决方案,工作得很好,但这是那么干净。
好东西,不知道那个。当我了解到脏模块时,我几乎感到兴奋! http://api.rubyonrails.org/classes/ActiveModel/Dirty.html – DiegoSalazar
这应该这样做:'def method_missing(method,* args,&block); self [:data] [method.to_s] .presence ||超级(方法,* args,&block);结束'这是动态的,但测试'profile.respond_to?:name'会失败 – MrYoshiji