Rails 3 - 如何...在数据库列字段中存储非结构化数据数据

时间:2010-09-30 04:55:48

标签: ruby-on-rails ruby-on-rails-3

我想学习在DATA字段中存储非结构化数据的智能方法

所以例如,如果我有表AuditLog,其字段为id | model_name |数据

在Data中,我希望存储基于model_name更改的各种类型的数据。我也想在数据中使用,因此出于性能原因,我可以使用JOIN输出这些记录。

实例 1 |照片| {photoid:1,photoname:“blah”} 1 |评论| {comment:1,commentcontent:“blah”,parent_type:“photo”,parent_id:“1”}

关于如何输入和输出的建议?

感谢

3 个答案:

答案 0 :(得分:4)

我不确定我是否理解你的问题。但无论如何我会尽力回答。

如果您需要将模型转换为JSON,那么它非常简单。只需在模型上调用.to_json即可。然后你可以将它存储在TEXT列中。

要阅读它,您有两个选择:

  • 将值读取为Ruby哈希值:ActiveSupport :: JSON.decode(some_json_text)

  • 将值读取为对象 - 原始模型:获取上面的哈希值并将其作为参数传递给SomeModel.new。但是在这种情况下你必须要小心 - 相关的集合不起作用,不会设置id等。

如何自定义行为有很多选项,而且不清楚什么是最适合您的。我建议您阅读此帮助页面:http://railsapi.com/doc/rails-v3.0.0/classes/ActiveModel/Serializers/JSON.html并根据需要自定义您的解决方案。

在下面的示例中,我没有在模型上使用.to_json方法,因为示例中的方法更加可自定义。例如,您可以控制关​​联的行为(如果它们将被存储到日志中),等等。阅读链接的文档,您将看到。

以下是示例实现(内部读取注释)

class AuditLog < ActiveRecord::Base

  #
  # Stores shallow snapshot (without nesting into associations) of current
  # model into the log in the JSON form
  #
  def self.audit(m)
    # encode passed model into the JSON text
    json = ActiveSupport::JSON.encode(m)
    # create new log record and store it to the database
    create(:model => m.class,
           :data => json)
  end

  #
  # Returns the logged item as a Ruby hash
  #
  # Your can access the result with ["attribute_name"]
  #
  def get_as_hash
    # get the hash
    result = ActiveSupport::JSON.decode(self.data)
    # normally the json is { model_name => { attributes ... } } and we want the
    # inner hash - so let's take it
    result.values.first
  end

  #
  # Returns the logged item as an original model (like Post, Comment, etc.)
  #
  # Beware that associations are filled only if they are stored in audit method
  # So in case of Post: post.comments will always return an empty array
  #
  def get_as_model
    # get hash
    hash = get_as_hash
    # create instance of the class model and pass the hash to init
    # attribute values
    m = self.model.constantize.new(hash)
    # the initializator above ignore :id so let's set it manually
    m.id = hash[:id]
    # return the model
    m
  end
end

你可以这样使用它:

class Post < ActiveRecord::Base
  has_many :comments

  # after any successful change store the model to log
  after_save :audit

  private

  # store the whole model to the log
  def audit
    AuditLog.audit(self)
  end
end

希望你会喜欢它!

答案 1 :(得分:0)

这听起来像是一个NoSQL数据库(例如MongoDB)的一个很好的用例。有一个名为Mongoid(http://mongoid.org/)的Rails宝石,它更容易。

如果要保留ActiveRecord,可以始终将数据字段序列化为哈希。 http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-serialize

您可以这样做:

class AuditLog < ActiveRecord::Base
  serialize :data, Hash
end

然后你就可以使用它:

@log = AuditLog.find(1)
@log.data = {:photo => {:photoid: 1, :photoname: "blah"}}

@log.data[:photo][:photoname] => "blah"

答案 2 :(得分:0)

这似乎是MongoDB的一项工作。我有一个类似的经历,我决定使用这个https://github.com/robertomiranda/mini_mongo

在Sinatra创建一个单独的服务