Paper Trail: создавать версию для родителя при изменении связанной модели?

Я работаю над приложением Rails, где мне нужно показать контрольный журнал для Record, который has_many Data. У меня есть paper_trail в моей записи и связанные модели Datum, и он отлично сохраняет их версии.

Однако мне нужно, чтобы одна версия для записи создавалась при каждом изменении одного или нескольких связанных данных. В настоящее время он создает версии для каждого изменяющегося Данного, но он создает версию Записи только в том случае, если атрибуты Записи изменяются; он не делает этого, когда связанные данные меняются.

Я попытался поместить touch_with_version в обратный вызов After_touch Record, например:

class Record < ActiveRecord::Base
  has_many :data

  has_paper_trail

  after_touch do |record|
    puts 'touched record'
    record.touch_with_version
  end

end

и

class Datum < ActiveRecord::Base
  belongs_to :record, :touch => true

  has_paper_trail

end

Обратный вызов after_touch срабатывает, но, к сожалению, он создает новую версию для каждого Datum, поэтому, когда создается запись, у нее уже есть около 10 версий, по одной для каждого Datum.

Есть ли способ узнать в обратных вызовах, была ли создана версия, чтобы я не создавал несколько? Например, проверить один из обратных вызовов Record и, если Datum уже запустил версию, больше не делать?

Спасибо!


person David Ham    schedule 09.10.2015    source источник
comment
Я думаю, что after_touch — хорошая идея, но может быть сложно предотвратить дублирование версий Record. Вместо этого, как насчет того, чтобы начать транзакцию, обновить Data, обновить Record, а затем зафиксировать транзакцию. Если все обновления происходят в одной транзакции, какой результат вы получите?   -  person Jared Beck    schedule 11.10.2015
comment
Транзакция звучит как то, что я хочу, но мне не нужно было ее создавать, я думаю, я просто получил ее бесплатно, потому что все Data belong_to Record, поэтому все эти сохранения просто происходят в ходе создания/обновления для Record. Еще одна проблема: если несколько Data создадут несколько версий для Record, я думаю, что мне нужно сохранить последнюю версию, а не первую, если я хочу, чтобы запись синхронизировалась с ее данными. Спасибо за ваш совет - я все еще новичок в Rails, и я не уверен, что еще достаточно думаю в Rails. Работаю над этим!   -  person David Ham    schedule 12.10.2015
comment
@JaredBeck, как я могу настроить эту транзакцию? Атрибуты данных Record уже находятся в транзакции (я думаю?) из-за ассоциации с Rails. Должен ли я отключить обратные вызовы paper_trail, например: has_paper_trail on: [], а затем создать свои собственные обратные вызовы after_create и after_update с помощью ``` Record.transaction do record.update record.touch_with_version end ```   -  person David Ham    schedule 12.10.2015
comment
Документацию по транзакциям в ActiveRecord можно начать здесь: guides.rubyonrails.org/   -  person Jared Beck    schedule 13.10.2015
comment
Если вы новичок в рельсах, я бы пока не рекомендовал использовать функцию ассоциаций PaperTrail, так как она является экспериментальной и имеет несколько известных проблем.   -  person Jared Beck    schedule 13.10.2015
comment
Спасибо за ссылку на страницу Руководства, я искал там транзакции, но не видел этого. И я видел предостережения об ассоциациях, но я не думаю, что какое-либо из них применимо ко мне; доступ к моим данным осуществляется только через запись. В итоге я подошел к проблеме с другой стороны; paper_trail сохраняет запись и данные (я нигде не теряю данные), поэтому я подхожу к проблеме с конца просмотра. Спасибо за вашу помощь!   -  person David Ham    schedule 14.10.2015
comment
@DavidHam Итак, вы отказались от создания одной версии Record.version при изменении связанной модели?   -  person Tom    schedule 14.12.2015
comment
Я так и сделал, но позже я обнаружил еще один подход, который еще не пробовал. (В моем случае свойство состояния родителя всегда менялось всякий раз, когда менялся дочерний Datum, так что это было спорным вопросом.) Но я думаю, что если бы я сделал belongs_to :record, touch: true в своем классе Datum, это создало бы временную метку, которую я хочу на моем Записывать.   -  person David Ham    schedule 15.12.2015


Ответы (1)


Это работает для меня.

class Place < ActiveRecord::Base
  has_paper_trail
  before_update :check_update

  def check_update
    return if changed_notably?

    tracking_has_many_associations = [ ... ]
    tracking_has_has_one_associations = [ ... ]

    tracking_has_many_associations.each do |a|
      send(a).each do |r|
        if r.send(:changed_notably?) || r.marked_for_destruction?
          self.touch
          return
        end
      end
    end
    tracking_has_one_associations.each do |a|
      r = send(a)
      if r.send(:changed_notably?) || r.marked_for_destruction?
        self.touch
        return
      end
    end
  end
end
person Tom    schedule 22.12.2015
comment
Возможно, вам придется добавить префикс вызова :changed_notably? with с вызовом paper_trail в первую очередь. например вместо changed_notably? => paper_trail.changed_notably?` - person Solomons_Ecclesiastes; 13.12.2016