2013-11-21 30 views
1

我有下面的类:访问属性里面散列列

class Profile < ActiveRecord::Base 
    serialize :data 
end 

档案具有保持序列化哈希单列data。我想将访问器定义为该散列,以便我可以执行profile.name而不是profile.data['name']。这在Rails中可能吗?

+0

这应该这样做:'def method_missing(method,* args,&block); self [:data] [method.to_s] .presence ||超级(方法,* args,&block);结束'这是动态的,但测试'profile.respond_to?:name'会失败 – MrYoshiji

回答

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/

1
class Profile < ActiveRecord::Base 
    serialize :data # always a hash or nil 

    def name 
    data[:name] if data 
    end 
end 
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 
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 
1

我要回答我的问题。它看起来像的ActiveRecord :: Store是什么,我想:

http://api.rubyonrails.org/classes/ActiveRecord/Store.html

所以我的课将成为:

class Profile < ActiveRecord::Base 
    store :data, accessors: [:name], coder: JSON 
end 

我敢肯定,每个人的解决方案,工作得很好,但这是那么干净。

+0

好东西,不知道那个。当我了解到脏模块时,我几乎感到兴奋! http://api.rubyonrails.org/classes/ActiveModel/Dirty.html – DiegoSalazar