[#479] Split GeneralizeJournals into separate, incremental migrations
This commit is contained in:
parent
498d3909cc
commit
52b83da8dd
|
@ -1,155 +0,0 @@
|
|||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2011 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class GeneralizeJournals < ActiveRecord::Migration
|
||||
def self.up
|
||||
# This is provided here for migrating up after the JournalDetails has been removed
|
||||
unless Object.const_defined?("JournalDetails")
|
||||
Object.const_set("JournalDetails", Class.new(ActiveRecord::Base))
|
||||
end
|
||||
|
||||
change_table :journals do |t|
|
||||
t.rename :journalized_id, :journaled_id
|
||||
t.rename :created_on, :created_at
|
||||
|
||||
t.integer :version, :default => 0, :null => false
|
||||
t.string :activity_type
|
||||
t.text :changes
|
||||
t.string :type
|
||||
|
||||
t.index :journaled_id
|
||||
t.index :activity_type
|
||||
t.index :created_at
|
||||
t.index :type
|
||||
end
|
||||
|
||||
Journal.all.group_by(&:journaled_id).each_pair do |id, journals|
|
||||
journals.sort_by(&:created_at).each_with_index do |j, idx|
|
||||
# Recast the basic Journal into it's STI journalized class so callbacks work (#467)
|
||||
klass_name = "#{j.journalized_type}Journal"
|
||||
j = j.becomes(klass_name.constantize)
|
||||
j.type = klass_name
|
||||
j.version = idx + 1
|
||||
# FIXME: Find some way to choose the right activity here
|
||||
j.activity_type = j.journalized_type.constantize.activity_provider_options.keys.first
|
||||
j.save(false)
|
||||
end
|
||||
end
|
||||
|
||||
change_table :journals do |t|
|
||||
t.remove :journalized_type
|
||||
end
|
||||
|
||||
# Reset class and subclasses, otherwise they will try to save using older attributes
|
||||
Journal.reset_column_information
|
||||
Journal.send(:subclasses).each do |klass|
|
||||
klass.reset_column_information if klass.respond_to?(:reset_column_information)
|
||||
end
|
||||
|
||||
# Build initial journals for all activity providers
|
||||
providers = Redmine::Activity.providers.collect {|k, v| v.collect(&:constantize) }.flatten.compact.uniq
|
||||
providers.each do |p|
|
||||
next unless p.table_exists? # Objects not in the DB yet need creation journal entries
|
||||
p.find(:all).each do |o|
|
||||
# Create initial journals
|
||||
new_journal = o.journals.build
|
||||
# Mock up a list of changes for the creation journal based on Class defaults
|
||||
new_attributes = o.class.new.attributes.except(o.class.primary_key,
|
||||
o.class.inheritance_column,
|
||||
:updated_on,
|
||||
:updated_at,
|
||||
:lock_version,
|
||||
:lft,
|
||||
:rgt)
|
||||
creation_changes = {}
|
||||
new_attributes.each do |name, default_value|
|
||||
# Set changes based on the initial value to current. Can't get creation value without
|
||||
# rebuiling the object history
|
||||
creation_changes[name] = [default_value, o.send(name)] # [initial_value, creation_value]
|
||||
end
|
||||
new_journal.changes = creation_changes
|
||||
new_journal.version = 1
|
||||
|
||||
if o.respond_to?(:author)
|
||||
new_journal.user = o.author
|
||||
elsif o.respond_to?(:user)
|
||||
new_journal.user = o.user
|
||||
end
|
||||
new_journal.save
|
||||
|
||||
# Backdate journal
|
||||
if o.respond_to?(:created_at)
|
||||
new_journal.update_attribute(:created_at, o.created_at)
|
||||
elsif o.respond_to?(:created_on)
|
||||
new_journal.update_attribute(:created_at, o.created_on)
|
||||
end
|
||||
p "Updating #{o}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Migrate journal changes now
|
||||
JournalDetails.all.each do |detail|
|
||||
journal = Journal.find(detail.journal_id)
|
||||
changes = journal.changes || {}
|
||||
if detail.property == 'attr' # Standard attributes
|
||||
changes[detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
elsif detail.property == 'cf' # Custom fields
|
||||
changes["custom_values_" + detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
elsif detail.property == 'attachment' # Attachment
|
||||
changes["attachments_" + detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
end
|
||||
journal.update_attribute(:changes, changes.to_yaml)
|
||||
end
|
||||
|
||||
# drop_table :journal_details
|
||||
end
|
||||
|
||||
def self.down
|
||||
# create_table "journal_details", :force => true do |t|
|
||||
# t.integer "journal_id", :default => 0, :null => false
|
||||
# t.string "property", :limit => 30, :default => "", :null => false
|
||||
# t.string "prop_key", :limit => 30, :default => "", :null => false
|
||||
# t.string "old_value"
|
||||
# t.string "value"
|
||||
# end
|
||||
|
||||
change_table "journals" do |t|
|
||||
t.rename :journaled_id, :journalized_id
|
||||
t.rename :created_at, :created_on
|
||||
|
||||
t.string :journalized_type, :limit => 30, :default => "", :null => false
|
||||
end
|
||||
|
||||
custom_field_names = CustomField.all.group_by(&:type)[IssueCustomField].collect(&:name)
|
||||
Journal.all.each do |j|
|
||||
# Can't used j.journalized.class.name because the model changes make it nil
|
||||
j.update_attribute(:journalized_type, j.type.to_s.sub("Journal","")) if j.type.present?
|
||||
end
|
||||
|
||||
change_table "journals" do |t|
|
||||
t.remove_index :journaled_id
|
||||
t.remove_index :activity_type
|
||||
t.remove_index :created_at
|
||||
t.remove_index :type
|
||||
|
||||
t.remove :type
|
||||
t.remove :version
|
||||
t.remove :activity_type
|
||||
t.remove :changes
|
||||
end
|
||||
|
||||
# add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id"
|
||||
# add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
#-- copyright
|
||||
# ChiliProject is a project management system.
|
||||
#
|
||||
# Copyright (C) 2010-2011 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class PrepareJournalsForActsAsJournalized < ActiveRecord::Migration
|
||||
def self.up
|
||||
# This is provided here for migrating up after the JournalDetails has been removed
|
||||
unless Object.const_defined?("JournalDetails")
|
||||
Object.const_set("JournalDetails", Class.new(ActiveRecord::Base))
|
||||
end
|
||||
|
||||
change_table :journals do |t|
|
||||
t.rename :journalized_id, :journaled_id
|
||||
t.rename :created_on, :created_at
|
||||
|
||||
t.integer :version, :default => 0, :null => false
|
||||
t.string :activity_type
|
||||
t.text :changes
|
||||
t.string :type
|
||||
|
||||
t.index :journaled_id
|
||||
t.index :activity_type
|
||||
t.index :created_at
|
||||
t.index :type
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.down
|
||||
change_table "journals" do |t|
|
||||
t.rename :journaled_id, :journalized_id
|
||||
t.rename :created_at, :created_on
|
||||
|
||||
t.remove_index :journaled_id
|
||||
t.remove_index :activity_type
|
||||
t.remove_index :created_at
|
||||
t.remove_index :type
|
||||
|
||||
t.remove :type
|
||||
t.remove :version
|
||||
t.remove :activity_type
|
||||
t.remove :changes
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
class UpdateJournalsForActsAsJournalized < ActiveRecord::Migration
|
||||
def self.up
|
||||
# This is provided here for migrating up after the JournalDetails has been removed
|
||||
unless Object.const_defined?("JournalDetails")
|
||||
Object.const_set("JournalDetails", Class.new(ActiveRecord::Base))
|
||||
end
|
||||
|
||||
say_with_time("Updating existing Journals...") do
|
||||
Journal.all.group_by(&:journaled_id).each_pair do |id, journals|
|
||||
journals.sort_by(&:created_at).each_with_index do |j, idx|
|
||||
# Recast the basic Journal into it's STI journalized class so callbacks work (#467)
|
||||
klass_name = "#{j.journalized_type}Journal"
|
||||
j = j.becomes(klass_name.constantize)
|
||||
j.type = klass_name
|
||||
j.version = idx + 1
|
||||
# FIXME: Find some way to choose the right activity here
|
||||
j.activity_type = j.journalized_type.constantize.activity_provider_options.keys.first
|
||||
j.save(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
change_table :journals do |t|
|
||||
t.remove :journalized_type
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
change_table "journals" do |t|
|
||||
t.string :journalized_type, :limit => 30, :default => "", :null => false
|
||||
end
|
||||
|
||||
custom_field_names = CustomField.all.group_by(&:type)[IssueCustomField].collect(&:name)
|
||||
Journal.all.each do |j|
|
||||
# Can't used j.journalized.class.name because the model changes make it nil
|
||||
j.update_attribute(:journalized_type, j.type.to_s.sub("Journal","")) if j.type.present?
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
class BuildInitialJournalsForActsAsJournalized < ActiveRecord::Migration
|
||||
def self.up
|
||||
# This is provided here for migrating up after the JournalDetails has been removed
|
||||
unless Object.const_defined?("JournalDetails")
|
||||
Object.const_set("JournalDetails", Class.new(ActiveRecord::Base))
|
||||
end
|
||||
|
||||
# Reset class and subclasses, otherwise they will try to save using older attributes
|
||||
Journal.reset_column_information
|
||||
Journal.send(:subclasses).each do |klass|
|
||||
klass.reset_column_information if klass.respond_to?(:reset_column_information)
|
||||
end
|
||||
|
||||
providers = Redmine::Activity.providers.collect {|k, v| v.collect(&:constantize) }.flatten.compact.uniq
|
||||
providers.each do |p|
|
||||
next unless p.table_exists? # Objects not in the DB yet need creation journal entries
|
||||
|
||||
say_with_time("Building initial journals for #{p.class_name}") do
|
||||
|
||||
p.find(:all).each do |o|
|
||||
# Create initial journals
|
||||
new_journal = o.journals.build
|
||||
# Mock up a list of changes for the creation journal based on Class defaults
|
||||
new_attributes = o.class.new.attributes.except(o.class.primary_key,
|
||||
o.class.inheritance_column,
|
||||
:updated_on,
|
||||
:updated_at,
|
||||
:lock_version,
|
||||
:lft,
|
||||
:rgt)
|
||||
creation_changes = {}
|
||||
new_attributes.each do |name, default_value|
|
||||
# Set changes based on the initial value to current. Can't get creation value without
|
||||
# rebuiling the object history
|
||||
creation_changes[name] = [default_value, o.send(name)] # [initial_value, creation_value]
|
||||
end
|
||||
new_journal.changes = creation_changes
|
||||
new_journal.version = 1
|
||||
|
||||
if o.respond_to?(:author)
|
||||
new_journal.user = o.author
|
||||
elsif o.respond_to?(:user)
|
||||
new_journal.user = o.user
|
||||
end
|
||||
new_journal.save
|
||||
new_journal.reload
|
||||
|
||||
# Backdate journal
|
||||
if o.respond_to?(:created_at)
|
||||
new_journal.update_attribute(:created_at, o.created_at)
|
||||
elsif o.respond_to?(:created_on)
|
||||
new_journal.update_attribute(:created_at, o.created_on)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.down
|
||||
# No-op
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
class AddChangesFromJournalDetailsForActsAsJournalized < ActiveRecord::Migration
|
||||
def self.up
|
||||
# This is provided here for migrating up after the JournalDetails has been removed
|
||||
unless Object.const_defined?("JournalDetails")
|
||||
Object.const_set("JournalDetails", Class.new(ActiveRecord::Base))
|
||||
end
|
||||
|
||||
say_with_time("Adding changes from JournalDetails") do
|
||||
JournalDetails.all.each do |detail|
|
||||
journal = Journal.find(detail.journal_id)
|
||||
changes = journal.changes || {}
|
||||
if detail.property == 'attr' # Standard attributes
|
||||
changes[detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
elsif detail.property == 'cf' # Custom fields
|
||||
changes["custom_values_" + detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
elsif detail.property == 'attachment' # Attachment
|
||||
changes["attachments_" + detail.prop_key.to_s] = [detail.old_value, detail.value]
|
||||
end
|
||||
journal.update_attribute(:changes, changes.to_yaml)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.down
|
||||
# No-op
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue