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 CHANGED
@@ -6,3 +6,4 @@ generators/trackzor_migration/templates/migration.rb
6
6
  generators/trackzor_migration/trackzor_migration_generator.rb
7
7
  init.rb
8
8
  lib/trackzor.rb
9
+ tasks/trackzor.rake
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.3') do |gem|
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
- aaa_present = self.respond_to?(:non_audited_columns)
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).select{|column| column =~ /(_updated_by|_updated_at)$/ }.each do |col|
21
- if col =~ /_updated_by$/
22
- belongs_to col.sub(/_updated_by$/, '_source').to_sym, :class_name => 'User', :foreign_key => col
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
- self.non_audited_columns << col if aaa_present
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 multiple attributes
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+.
@@ -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.3"
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-22}
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.3
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-22 00:00:00 -05:00
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