trackzor 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest +1 -0
- data/README.rdoc +16 -0
- data/Rakefile +1 -1
- data/lib/trackzor.rb +65 -7
- data/tasks/trackzor.rake +40 -0
- data/trackzor.gemspec +4 -4
- metadata +4 -2
data/Manifest
CHANGED
data/README.rdoc
CHANGED
@@ -22,3 +22,19 @@ Or, if you're also using acts_as_audited, its as_user method is supported:
|
|
22
22
|
end
|
23
23
|
|
24
24
|
For each trackzored [ATTR]_updated_by column, a belongs_to association (:[ATTR]_source) is added to link to the user.
|
25
|
+
|
26
|
+
== Sharing and Merging Tables
|
27
|
+
|
28
|
+
Trackzor provides rake tasks for consolidating development databases.
|
29
|
+
When using Trackzor as a gem, copy trackzor.rake from the gem's tasks directory to your application's tasks directory.
|
30
|
+
|
31
|
+
Merging from Person A to Person B:
|
32
|
+
Person A: > rake trackzor_merge:dump TABLE=users
|
33
|
+
/path/printed/to/dump/users_for_merge.sql
|
34
|
+
|
35
|
+
Person B: > rake trackzor_merge:load CLASS=User FILE=users_for_merge.sql COLUMN=email
|
36
|
+
Merging joe@bob.com {:zip_code => ['12345', '54321']}
|
37
|
+
Creating new@guy.com
|
38
|
+
...
|
39
|
+
|
40
|
+
Trackzor will load the DB dump into a temporary table and merge data that is newer (based on ATTR_updated_at if available, otherwise updated_at).
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('trackzor', '0.1.
|
5
|
+
Echoe.new('trackzor', '0.1.5') do |gem|
|
6
6
|
gem.description = "Track ATTR_updated_at and ATTR_updated_by"
|
7
7
|
gem.url = "http://github.com/corneldm/trackzor"
|
8
8
|
gem.author = "David Cornelius"
|
data/lib/trackzor.rb
CHANGED
@@ -6,6 +6,8 @@ module Trackzor
|
|
6
6
|
module ClassMethods
|
7
7
|
def trackzored(options = {})
|
8
8
|
class_inheritable_reader :trackzor_exempt_columns
|
9
|
+
class_inheritable_reader :trackzor_maintained_columns
|
10
|
+
class_inheritable_reader :trackzored_columns
|
9
11
|
|
10
12
|
if options[:only]
|
11
13
|
except = self.column_names - options[:only].flatten.map(&:to_s)
|
@@ -14,14 +16,34 @@ module Trackzor
|
|
14
16
|
except |= Array(options[:except]).collect(&:to_s) if options[:except]
|
15
17
|
end
|
16
18
|
write_inheritable_attribute :trackzor_exempt_columns, except
|
17
|
-
|
19
|
+
|
20
|
+
the_trackzored_columns = []
|
21
|
+
the_trackzor_maintained_columns = []
|
18
22
|
|
19
23
|
# create ATTR_source associations
|
20
|
-
(self.column_names - self.trackzor_exempt_columns).
|
21
|
-
|
22
|
-
|
24
|
+
(self.column_names - self.trackzor_exempt_columns).each do |column|
|
25
|
+
has_updated_by_col = self.column_names.include?("#{column}_updated_by")
|
26
|
+
has_updated_at_col = self.column_names.include?("#{column}_updated_at")
|
27
|
+
|
28
|
+
if has_updated_by_col || has_updated_at_col
|
29
|
+
the_trackzored_columns << column
|
30
|
+
|
31
|
+
if has_updated_by_col
|
32
|
+
belongs_to "#{column}_source".to_sym, :class_name => 'User', :foreign_key => "#{column}_updated_by"
|
33
|
+
the_trackzor_maintained_columns << "#{column}_updated_by"
|
34
|
+
end
|
35
|
+
|
36
|
+
if has_updated_at_col
|
37
|
+
the_trackzor_maintained_columns << "#{column}_updated_at"
|
38
|
+
end
|
23
39
|
end
|
24
|
-
|
40
|
+
end
|
41
|
+
write_inheritable_attribute :trackzored_columns, the_trackzored_columns
|
42
|
+
write_inheritable_attribute :trackzor_maintained_columns, the_trackzor_maintained_columns
|
43
|
+
|
44
|
+
if self.respond_to?(:non_audited_columns)
|
45
|
+
nac = self.non_audited_columns + the_trackzor_maintained_columns
|
46
|
+
write_inheritable_attribute :non_audited_columns, nac
|
25
47
|
end
|
26
48
|
|
27
49
|
validate :trackzor_assign_and_validate
|
@@ -54,7 +76,7 @@ module Trackzor
|
|
54
76
|
end
|
55
77
|
end
|
56
78
|
|
57
|
-
# force update of
|
79
|
+
# update multiple attributes and force update of trackzored attributes
|
58
80
|
def will_update_attributes!(new_attributes, guard_protected_attributes = true)
|
59
81
|
return if new_attributes.nil?
|
60
82
|
attributes = new_attributes.dup
|
@@ -69,7 +91,7 @@ module Trackzor
|
|
69
91
|
else
|
70
92
|
if respond_to?("#{k}=")
|
71
93
|
send("#{k}=", v)
|
72
|
-
send("#{k}_will_change!")
|
94
|
+
send("#{k}_will_change!") if self.trackzored_columns.include?(k)
|
73
95
|
else
|
74
96
|
raise "unknown attribute: #{k}"
|
75
97
|
end
|
@@ -79,6 +101,42 @@ module Trackzor
|
|
79
101
|
assign_multiparameter_attributes(multi_parameter_attributes)
|
80
102
|
save!
|
81
103
|
end
|
104
|
+
|
105
|
+
# merge record with another, accepting the latest values available
|
106
|
+
def merge_with(other, unique_id_col = 'id')
|
107
|
+
raise "unmergable objects" if other.class.column_names != self.class.column_names || self.send(unique_id_col.to_sym) != other.send(unique_id_col.to_sym)
|
108
|
+
|
109
|
+
column_names = self.class.column_names
|
110
|
+
|
111
|
+
self.trackzored_columns.each do |tc|
|
112
|
+
has_updated_by_col = column_names.include?("#{tc}_updated_by")
|
113
|
+
has_updated_at_col = column_names.include?("#{tc}_updated_at")
|
114
|
+
|
115
|
+
if has_updated_at_col
|
116
|
+
self_time = self.send("#{tc}_updated_at".to_sym)
|
117
|
+
other_time = other.send("#{tc}_updated_at".to_sym)
|
118
|
+
else
|
119
|
+
self_time = self.updated_at
|
120
|
+
other_time = other.updated_at
|
121
|
+
end
|
122
|
+
|
123
|
+
if self_time.nil? || (!other_time.nil? && other_time > self_time)
|
124
|
+
self.send("#{tc}_updated_at=".to_sym, other_time) if has_updated_at_col
|
125
|
+
self.send("#{tc}_updated_by=".to_sym, other.send("#{tc}_updated_by".to_sym)) if has_updated_by_col
|
126
|
+
self.send("#{tc}=".to_sym, other.send(tc.to_sym))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
if other.updated_at > self.updated_at
|
131
|
+
(column_names - self.trackzored_columns - self.trackzor_maintained_columns).each do |c|
|
132
|
+
self.send("#{c}=".to_sym, other.send(c.to_sym))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
puts "Merged #{self.send(unique_id_col.to_sym)}: #{self.changes.inspect}" unless self.changes.empty?
|
137
|
+
self.send(:update_without_callbacks)
|
138
|
+
end
|
139
|
+
|
82
140
|
end # InstanceMethods
|
83
141
|
|
84
142
|
# All X attribute changes where X_updated_by exists will be recorded as made by +user+.
|
data/tasks/trackzor.rake
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
namespace :trackzor_merge do
|
2
|
+
MERGE_TABLE_SUFFIX = "_for_merge"
|
3
|
+
|
4
|
+
task :dump do
|
5
|
+
raise ArgumentError, "must provide TABLE to dump, id is assumed PK unless TABLE_PK is set" unless ENV['TABLE']
|
6
|
+
pk = ENV['TABLE_PK'] || 'id'
|
7
|
+
config = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
|
8
|
+
sub_file = "#{RAILS_ROOT}/tmp/#{ENV['TABLE']}#{MERGE_TABLE_SUFFIX}.sql"
|
9
|
+
system "mysqldump --user=#{config[RAILS_ENV]['username']} --password=#{config[RAILS_ENV]['password']} #{config[RAILS_ENV]['database']} #{ENV['TABLE']} > #{sub_file}_1"
|
10
|
+
system "sed 's/`#{ENV['TABLE']}`/`#{ENV['TABLE']}#{MERGE_TABLE_SUFFIX}`/g' #{sub_file}_1 > #{sub_file}_2"
|
11
|
+
system "sed 's/PRIMARY KEY (`#{pk}`),/PRIMARY KEY (`#{pk}`)/g' #{sub_file}_2 > #{sub_file}_3"
|
12
|
+
system "grep -Ev 'index_#{ENV['TABLE']}_on' #{sub_file}_3 > #{sub_file}"
|
13
|
+
system "rm #{sub_file}_*"
|
14
|
+
puts sub_file
|
15
|
+
end
|
16
|
+
|
17
|
+
task :load => :environment do
|
18
|
+
raise ArgumentError, "must provide target CLASS to merge into, FILE for sql dump, unique identifying column assumed to be id unless COLUMN is set" unless ENV['CLASS'] && ENV['FILE']
|
19
|
+
|
20
|
+
col = ENV['COLUMN'] || 'id'
|
21
|
+
model = ENV['CLASS'].camelize.constantize
|
22
|
+
merge_model = model.clone
|
23
|
+
merge_model.table_name += MERGE_TABLE_SUFFIX
|
24
|
+
|
25
|
+
config = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
|
26
|
+
system "mysql --user=#{config[RAILS_ENV]['username']} --password=#{config[RAILS_ENV]['password']} #{config[RAILS_ENV]['database']} < #{ENV['FILE']}"
|
27
|
+
|
28
|
+
merge_model.find(:all).each do |record_to_merge|
|
29
|
+
if record = model.send("find_by_#{col}".to_sym, record_to_merge.send(col.to_sym))
|
30
|
+
record.merge_with(record_to_merge)
|
31
|
+
else
|
32
|
+
new_record = model.new(record_to_merge.attributes)
|
33
|
+
# set unique id expliciting in case it's the PK
|
34
|
+
new_record.send("#{col}=".to_sym, record_to_merge.send(col.to_sym))
|
35
|
+
new_record.send(:create_without_callbacks)
|
36
|
+
puts "Created #{new_record.send(col.to_sym)}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/trackzor.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{trackzor}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["David Cornelius"]
|
9
|
-
s.date = %q{2010-01-
|
9
|
+
s.date = %q{2010-01-25}
|
10
10
|
s.description = %q{Track ATTR_updated_at and ATTR_updated_by}
|
11
11
|
s.email = %q{david.cornelius@bluefishwireless.net}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "README.rdoc", "lib/trackzor.rb"]
|
13
|
-
s.files = ["CHANGELOG", "Manifest", "README.rdoc", "Rakefile", "generators/trackzor_migration/templates/migration.rb", "generators/trackzor_migration/trackzor_migration_generator.rb", "init.rb", "lib/trackzor.rb", "trackzor.gemspec"]
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "README.rdoc", "lib/trackzor.rb", "tasks/trackzor.rake"]
|
13
|
+
s.files = ["CHANGELOG", "Manifest", "README.rdoc", "Rakefile", "generators/trackzor_migration/templates/migration.rb", "generators/trackzor_migration/trackzor_migration_generator.rb", "init.rb", "lib/trackzor.rb", "tasks/trackzor.rake", "trackzor.gemspec"]
|
14
14
|
s.homepage = %q{http://github.com/corneldm/trackzor}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Trackzor", "--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trackzor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Cornelius
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-25 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,6 +23,7 @@ extra_rdoc_files:
|
|
23
23
|
- CHANGELOG
|
24
24
|
- README.rdoc
|
25
25
|
- lib/trackzor.rb
|
26
|
+
- tasks/trackzor.rake
|
26
27
|
files:
|
27
28
|
- CHANGELOG
|
28
29
|
- Manifest
|
@@ -32,6 +33,7 @@ files:
|
|
32
33
|
- generators/trackzor_migration/trackzor_migration_generator.rb
|
33
34
|
- init.rb
|
34
35
|
- lib/trackzor.rb
|
36
|
+
- tasks/trackzor.rake
|
35
37
|
- trackzor.gemspec
|
36
38
|
has_rdoc: true
|
37
39
|
homepage: http://github.com/corneldm/trackzor
|