Rails 3 - как ... Хранение неструктурированных данных в поле столбца базы данных - PullRequest
2 голосов
/ 30 сентября 2010

Я хотел бы узнать, как правильно хранить неструктурированные данные в поле DATA

например, если у меня есть таблица AuditLog с полями id | имя модели | данные

И в Data я хочу хранить различные типы данных, которые меняются в зависимости от имени модели. Я также хочу это в данных, чтобы я мог выводить эти записи без использования JOIN по соображениям производительности.

Примеры 1 | фото | {photoid: 1, имя пользователя: "бла"} 1 | комментарий | {comment: 1, commentcontent: «бла», parent_type: «photo», parent_id: «1»}

Предложения по вводу и выводу?

спасибо

Ответы [ 3 ]

4 голосов
/ 30 сентября 2010

Я не уверен, правильно ли я понял ваш вопрос.Но я все равно постараюсь ответить на него.

Если вам нужно преобразовать модель в JSON, это очень просто.Просто позвоните .to_json на модель.Затем вы можете сохранить его в столбце TEXT.

Чтобы прочитать его обратно, у вас есть два варианта:

  • прочитать значение как хеш Ruby: ActiveSupport :: JSON.decode(some_json_text)

  • считайте значение как объект - исходную модель: возьмите полученный выше хеш и передайте его SomeModel.new в качестве параметра.Но в этом случае вы должны быть осторожны - связанные коллекции не будут работать, идентификатор не будет установлен и т. Д.

Есть много вариантов, как настроить поведение, и не ясно, чтолучшее для тебя.Я рекомендую прочитать эту страницу справки: 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

Надеюсь, вам понравится!

0 голосов
/ 21 января 2015

Это похоже на работу с MongoDB.У меня был подобный опыт в тот момент, когда я решил создать отдельный сервис в Синатре, используя этот https://github.com/robertomiranda/mini_mongo

0 голосов
/ 02 октября 2010

Звучит так, как будто это отличный вариант использования базы данных NoSQL, такой как MongoDB.Для него есть гем Rails под названием Mongoid (http://mongoid.org/), который облегчает его.

Если вы хотите сохранить ActiveRecord, вы всегда можете сериализовать поле данных как хеш.Вы бы сделали что-то вроде:

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

Тогда вы можете использовать это как:

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

@log.data[:photo][:photoname] => "blah"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...