哈希列内的访问属性

时间:2013-11-21 16:29:46

标签: ruby-on-rails activerecord

我有以下课程:

class Profile < ActiveRecord::Base
  serialize :data
end

配置文件有一个包含序列化哈希的列data。我想在这个哈希中定义访问器,以便我可以执行profile.name而不是profile.data['name']。这可能在Rails中吗?

5 个答案:

答案 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,然后调用@profiledata内关键字的任何属性。因此,调用@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