custom_change_messages 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +105 -0
- data/Rakefile +23 -0
- data/lib/custom_change_messages.rb +1 -0
- data/lib/custom_change_messages/active_record.rb +184 -0
- data/test/active_record_test.rb +115 -0
- data/test/custom_change_messages_test.rb +25 -0
- data/test/database.yml +3 -0
- data/test/schema.rb +20 -0
- data/test/test_helper.rb +35 -0
- metadata +111 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [Jeremy Olliver]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
CustomChangeMessages
|
2
|
+
====================
|
3
|
+
|
4
|
+
CustomChangeMessages is a rails plugin for providing a nicely formatted log message recording any edits made to an active record object.
|
5
|
+
This is based off of the ActiveRecord::Dirty module, making this plugin compatible with rails versions 2.1 and up. There is little to no configuration required, with all columns included by default (except for id, and created_at, updated_at timestamps), and belongs_to associations handled nicely with the default options configurable.
|
6
|
+
|
7
|
+
Usage
|
8
|
+
=====
|
9
|
+
|
10
|
+
# In a controllers #update action
|
11
|
+
|
12
|
+
def update
|
13
|
+
@post = Post.find(params[:id])
|
14
|
+
@post.attributes = params[:post]
|
15
|
+
@changes = @post.change_messages
|
16
|
+
# Use this array to either log history, display in a flash message, or in a mailer.
|
17
|
+
# => ["Title has changed from 'Ruby on Rails plugin' to '[Update] Ruby on Rails plugin'", "Category has changed from 'Ruby' to 'Ruby on Rails'"]
|
18
|
+
@post.save!
|
19
|
+
end
|
20
|
+
|
21
|
+
API
|
22
|
+
===
|
23
|
+
|
24
|
+
ActiveRecord extensions:
|
25
|
+
|
26
|
+
change_message_for(attribute) # Returns a string message representation of the attribute that has changed
|
27
|
+
change_messages # Returns an array of the messages for each changed attribute
|
28
|
+
|
29
|
+
Installation
|
30
|
+
============
|
31
|
+
|
32
|
+
gem install custom_change_messages
|
33
|
+
|
34
|
+
Rails 2.X
|
35
|
+
# config/environment.rb
|
36
|
+
config.gem "custom_change_messages"
|
37
|
+
|
38
|
+
Rails 3.X
|
39
|
+
# Gemfile
|
40
|
+
gem "custom_change_messages"
|
41
|
+
|
42
|
+
|
43
|
+
Requirements: active record, version 2.1 or greater, if you use an earlier version you can try using http://code.bitsweat.net/svn/dirty which backports the ActiveRecord::Dirty code that this gem depends on to earlier rails versions.
|
44
|
+
|
45
|
+
|
46
|
+
Detailed Example
|
47
|
+
================
|
48
|
+
|
49
|
+
The main use of this is to help clean up controller actions, such as:
|
50
|
+
|
51
|
+
class ItemsController < ApplicationController
|
52
|
+
|
53
|
+
def update
|
54
|
+
@item.attributes = params[:item]
|
55
|
+
Mailer.deliver_item_update(@item, @item.change_messages.to_sentence)
|
56
|
+
@item.save!
|
57
|
+
|
58
|
+
rescue ActiveRecord::RecordInvalid => e
|
59
|
+
flash[:error] = e.reord.error_messages
|
60
|
+
redirect_to item_url(@item)
|
61
|
+
end
|
62
|
+
#...
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
@item.change_messages.to_sentence will return human readable mesages such as:
|
67
|
+
=> "Description has changed from 'Nice and easy' to 'This task is now rather long and arduous', User has changed from 'Jeremy' to 'Guy', and Due Date has been rescheduled from '09/11/2008' to '10/11/2008'"
|
68
|
+
|
69
|
+
The messages for each attribute are also customizable, which is especially handy for dealing with belongs_to
|
70
|
+
assocations. Here's a more complicated example:
|
71
|
+
|
72
|
+
Use the custom_message_for method to customize the message for the attribute, specifying :display => :name
|
73
|
+
will use the method/attribute :name for displaying the record that the item belongs_to
|
74
|
+
|
75
|
+
The skip_message_for method can be used to prevent stop any changes to a particular attribute showing up
|
76
|
+
|
77
|
+
class Item < ActiveRecord::Base
|
78
|
+
belongs_to :person
|
79
|
+
|
80
|
+
custom_message_for :person, :display => :username # display the person's username instead of the id
|
81
|
+
custom_message_for :due_on, :as => "Due Date", :message => "has been rescheduled", :format => :pretty_print_date
|
82
|
+
# change the syntax of the message for working with dates, because it makes more sense that way
|
83
|
+
|
84
|
+
# this method is used for formatting the due_on field when it changes
|
85
|
+
def pretty_print_date(value = self.due_on)
|
86
|
+
value.strftime("%d/%m/%Y")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Person < ActiveRecord::Base
|
91
|
+
custom_message_for :username, :as => "Name"
|
92
|
+
skip_message_for :internal_calculation
|
93
|
+
end
|
94
|
+
|
95
|
+
p = Person.create!(:username => "Jeremy")
|
96
|
+
p2 = Person.create!(:username => "Optimus Prime")
|
97
|
+
i = Item.create!(:name => "My Task", :description => nil, :person => p, :due_on => Date.today)
|
98
|
+
i.attributes = {:person => p2, :description => "This task is difficult, might need some help"}
|
99
|
+
|
100
|
+
i.change_messages
|
101
|
+
=> ["Due Date has been rescheduled from '4/12/2008' to '5/12/2008'", "Person has changed from 'Jeremy' to 'Optimus Prime'", "Description has changed from '' to 'This task is difficult, might need some help'"]
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
Copyright (c) 2008 Jeremy Olliver, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc 'Run tests for custom_change_messages'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the custom_change_messages gem.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'Custom Change Messages'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'custom_change_messages/active_record'
|
@@ -0,0 +1,184 @@
|
|
1
|
+
ActiveRecord::Base.class_eval do
|
2
|
+
|
3
|
+
# hash and array to keep track of the customised messages, belongs_to associations, and any skipped attributes
|
4
|
+
class_inheritable_hash :custom_dirty_messages # The watched attributes with configuration options {:field_name => options, ...}
|
5
|
+
class_inheritable_hash :belongs_to_key_mapping
|
6
|
+
|
7
|
+
CUSTOM_CHANGE_MESSAGE_DEFAULTS = {:message => "has changed", :prefix => "from", :suffix => "to"}
|
8
|
+
DEFAULT_SKIPPED_COLUMNS = [:updated_at, :created_at, :id]
|
9
|
+
|
10
|
+
DEFAULT_BELONGS_TO_DISPLAY_OPTIONS = [:name, :title, :display, :description]
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def initialise_default_change_messages
|
15
|
+
unless self.custom_dirty_messages
|
16
|
+
self.custom_dirty_messages = {}
|
17
|
+
self.belongs_to_key_mapping = {}
|
18
|
+
|
19
|
+
model_columns = self.column_names.collect(&:to_sym)
|
20
|
+
|
21
|
+
# Don't include foreign keys for belongs_to associations by default, they must be added manually
|
22
|
+
self.reflect_on_all_associations(:belongs_to).each do |association|
|
23
|
+
# model_columns -= [association.primary_key_name.to_sym] # Remove the key name from the attributes that will be watched by default
|
24
|
+
self.belongs_to_key_mapping.merge!(association.primary_key_name.to_sym => association.name)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Register each column with default options
|
28
|
+
model_columns.each do |column_name|
|
29
|
+
key = key_name_for(column_name)
|
30
|
+
next if DEFAULT_SKIPPED_COLUMNS.include?(key)
|
31
|
+
# custom_dirty_messages[key] = CUSTOM_CHANGE_MESSAGE_DEFAULTS.clone
|
32
|
+
custom_message_for(key)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def custom_message_for(*attr_names)
|
38
|
+
initialise_default_change_messages
|
39
|
+
|
40
|
+
options = attr_names.extract_options!
|
41
|
+
options.symbolize_keys!
|
42
|
+
|
43
|
+
attr_names.each do |attribute|
|
44
|
+
key = key_name_for(attribute)
|
45
|
+
|
46
|
+
if is_association?(key)
|
47
|
+
association = self.reflect_on_association(key)
|
48
|
+
display_method = options[:display]
|
49
|
+
raise "Incorrect :display option. #{display_method} is undefined for #{association.class_name}" if display_method && !method_or_attribute_exists(association, display_method)
|
50
|
+
display_method ||= find_default_display_method(association)
|
51
|
+
puts "***Warning*** couldn't detect a display method for #{key.to_s}, please set a display option e.g. custom_message_for :#{key.to_s}, :display => :my_display_method (where #{association.class_name}#my_display_method) is defined otherwise #to_s will be used as the default" unless display_method
|
52
|
+
display_method ||= :to_s
|
53
|
+
|
54
|
+
defaults = CUSTOM_CHANGE_MESSAGE_DEFAULTS.merge({:as => association.name.to_s.humanize.titleize, :display => :to_s})
|
55
|
+
options = defaults.merge(options).merge({:type => :belongs_to})
|
56
|
+
end
|
57
|
+
|
58
|
+
if self.custom_dirty_messages[key]
|
59
|
+
# override defaults
|
60
|
+
self.custom_dirty_messages[key].merge!(options)
|
61
|
+
else
|
62
|
+
# Set values for any not already being watched
|
63
|
+
self.custom_dirty_messages.merge!({key => options})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def skip_message_for(*attr_names)
|
69
|
+
initialise_default_change_messages
|
70
|
+
|
71
|
+
attr_names.extract_options!
|
72
|
+
attr_names.each do |column_name|
|
73
|
+
key = key_name_for(column_name)
|
74
|
+
self.custom_dirty_messages.delete(key)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_association?(attribute)
|
79
|
+
belongs_to_key_mapping.keys.include?(attribute.to_sym) || belongs_to_key_mapping.values.include?(attribute.to_sym)
|
80
|
+
end
|
81
|
+
|
82
|
+
def key_name_for(attribute)
|
83
|
+
attribute = attribute.to_sym
|
84
|
+
if is_association?(attribute)
|
85
|
+
# Use the association name for belongs_to (could be already passed in)
|
86
|
+
belongs_to_key_mapping[attribute] || attribute
|
87
|
+
else
|
88
|
+
attribute
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def method_or_attribute_exists(association, method)
|
95
|
+
klass = association.class_name.constantize
|
96
|
+
(klass.column_names + klass.instance_methods).include?(method.to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
def find_default_display_method(association)
|
100
|
+
DEFAULT_BELONGS_TO_DISPLAY_OPTIONS.each do |meth_name|
|
101
|
+
return meth_name if method_or_attribute_exists(association, meth_name)
|
102
|
+
end
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
def change_messages
|
109
|
+
self.class.initialise_default_change_messages
|
110
|
+
|
111
|
+
messages = []
|
112
|
+
changes.each do |attribute, diff|
|
113
|
+
key = self.class.key_name_for(attribute) # belongs_to association name, or column_name
|
114
|
+
|
115
|
+
if self.class.custom_dirty_messages.keys.include?(key)
|
116
|
+
messages << change_message_for(key, diff)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
messages
|
120
|
+
end
|
121
|
+
|
122
|
+
def change_message_for(attribute, changes = nil)
|
123
|
+
self.class.initialise_default_change_messages
|
124
|
+
|
125
|
+
column_name = column_name_for(attribute)
|
126
|
+
changes ||= self.send((column_name.to_s + "_change").to_sym)
|
127
|
+
|
128
|
+
key = self.class.key_name_for(attribute)
|
129
|
+
|
130
|
+
val = "#{attr_name(key)} #{message_option_value(key, :message)}"
|
131
|
+
val += " #{message_option_value(key, :prefix)} \'#{attr_display(key, changes.first)}\'" unless message_option_value(key, :no_prefix)
|
132
|
+
val += " #{message_option_value(key, :suffix)} \'#{attr_display(key, changes.last)}\'" unless message_option_value(key, :no_suffix)
|
133
|
+
val
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def column_name_for(attribute)
|
139
|
+
attribute = attribute.to_sym
|
140
|
+
if self.class.belongs_to_key_mapping.values.include?(attribute)
|
141
|
+
self.class.belongs_to_key_mapping.to_a.select {|col, assoc_name| assoc_name == attribute }.first.first
|
142
|
+
else
|
143
|
+
attribute
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# check if it's an association name, or if the attribute is being watched
|
148
|
+
def attr_name(key)
|
149
|
+
value = if self.class.custom_dirty_messages[key]
|
150
|
+
if (name = self.class.custom_dirty_messages[key][:as])
|
151
|
+
name
|
152
|
+
else
|
153
|
+
key
|
154
|
+
end
|
155
|
+
else
|
156
|
+
key
|
157
|
+
end
|
158
|
+
value.to_s.humanize.titleize
|
159
|
+
end
|
160
|
+
|
161
|
+
def attr_display(key, value)
|
162
|
+
if self.class.custom_dirty_messages[key]
|
163
|
+
if (meth = self.class.custom_dirty_messages[key][:format])
|
164
|
+
return self.send(meth, value)
|
165
|
+
elsif (meth = self.class.custom_dirty_messages[key][:display]) && self.class.is_association?(key)
|
166
|
+
assoc = self.class.reflect_on_association(key)
|
167
|
+
raise "must set the :display option for belongs_to associations e.g. :display => :name where name is a method on the parent object" unless meth
|
168
|
+
finder = ("find_by_" + assoc.klass.primary_key).to_sym
|
169
|
+
return assoc.klass.send(finder, value).send(meth.to_sym)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
return value.to_s
|
173
|
+
end
|
174
|
+
|
175
|
+
def message_option_value(key, option)
|
176
|
+
if self.class.custom_dirty_messages[key]
|
177
|
+
self.class.custom_dirty_messages[key][option] || CUSTOM_CHANGE_MESSAGE_DEFAULTS[option]
|
178
|
+
else
|
179
|
+
CUSTOM_CHANGE_MESSAGE_DEFAULTS[option]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
load_schema
|
4
|
+
|
5
|
+
class Person < ActiveRecord::Base
|
6
|
+
custom_message_for :username, :as => "Name"
|
7
|
+
skip_message_for :internal_calculation
|
8
|
+
end
|
9
|
+
|
10
|
+
class Category < ActiveRecord::Base
|
11
|
+
def to_s
|
12
|
+
name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Item < ActiveRecord::Base
|
17
|
+
DATEFORMAT = "%d/%m/%Y"
|
18
|
+
belongs_to :person
|
19
|
+
belongs_to :category
|
20
|
+
|
21
|
+
custom_message_for :person, :display => :username
|
22
|
+
custom_message_for :due_on, :as => "Due Date", :message => "has been rescheduled", :format => :pretty_print_date
|
23
|
+
|
24
|
+
def pretty_print_date(value = self.due_on)
|
25
|
+
value.strftime(DATEFORMAT)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class ActiveRecordTest < Test::Unit::TestCase
|
31
|
+
|
32
|
+
def test_active_record_extension
|
33
|
+
i = Item.create!
|
34
|
+
assert i.respond_to?(:change_messages)
|
35
|
+
assert i.respond_to?(:change_message_for)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_ignores_timestamps
|
39
|
+
i = Item.create!
|
40
|
+
i.attributes = {:created_at => Date.tomorrow, :updated_at => Date.tomorrow}
|
41
|
+
|
42
|
+
assert i.change_messages.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_belongs_to_and_keys_ignored_by_default
|
46
|
+
c1 = Category.create(:name => "Updates")
|
47
|
+
c2 = Category.create(:name => "Posts")
|
48
|
+
i = Item.create!(:category => c1)
|
49
|
+
|
50
|
+
i.category = c2
|
51
|
+
|
52
|
+
assert_equal ["Category has changed from 'Updates' to 'Posts'"], i.change_messages # The belongs_to association (and it's foreign key) should be ignored by default
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_unwatching
|
56
|
+
p = Person.create!(:username => "Robot", :internal_calculation => 1)
|
57
|
+
p.internal_calculation = 42
|
58
|
+
assert p.change_messages.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_labeling_attributes
|
62
|
+
# ensure associations are given the correct name. In this case username has been renamed to 'Name'
|
63
|
+
u = Person.create!(:username => "Jeremy")
|
64
|
+
u.username = "Jeremy O"
|
65
|
+
|
66
|
+
assert_equal "Name has changed from \'Jeremy\' to \'Jeremy O\'", u.change_message_for(:username)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_associations_loaded
|
70
|
+
i = Item.create!(:name => "My Cool Task")
|
71
|
+
assert i.class.custom_dirty_messages[:person]
|
72
|
+
assert_equal :belongs_to, i.class.custom_dirty_messages[:person][:type]
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_display_of_associations
|
76
|
+
u = Person.create!(:username => "Jeremy")
|
77
|
+
u2 = Person.create!(:username => "Guy")
|
78
|
+
i = Item.create!(:name => "My Task", :description => "super", :person => u)
|
79
|
+
i.person = u2
|
80
|
+
|
81
|
+
assert_equal "Person has changed from \'Jeremy\' to \'Guy\'", i.change_message_for(:person)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_handling_of_nil_attrs
|
85
|
+
i = Item.create!(:name => "Namae wa", :description => nil)
|
86
|
+
i.description = "Japanese sentence"
|
87
|
+
|
88
|
+
assert_nothing_raised do
|
89
|
+
i.change_messages
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_formatting_attributes
|
94
|
+
i = Item.create!(:name => "Task", :due_on => Date.today)
|
95
|
+
i.due_on = Date.tomorrow
|
96
|
+
|
97
|
+
today = Date.today.strftime(Item::DATEFORMAT)
|
98
|
+
tomorrow = Date.tomorrow.strftime(Item::DATEFORMAT)
|
99
|
+
assert_equal "Due Date has been rescheduled from '#{today}' to '#{tomorrow}'", i.change_message_for(:due_on)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_full_sentence_changes
|
103
|
+
p = Person.create!(:username => "Jeremy")
|
104
|
+
p2 = Person.create!(:username => "Optimus")
|
105
|
+
i = Item.create!(:name => "My Task", :description => "Nice and easy", :person => p, :due_on => Date.today)
|
106
|
+
i.attributes = {:person => p2, :description => "This task is difficult, might need some help", :due_on => Date.tomorrow }
|
107
|
+
|
108
|
+
today = Date.today.strftime(Item::DATEFORMAT)
|
109
|
+
tomorrow = Date.tomorrow.strftime(Item::DATEFORMAT)
|
110
|
+
|
111
|
+
assert_equal "Due Date has been rescheduled from '#{today}' to '#{tomorrow}', Person has changed from 'Jeremy' to 'Optimus', and Description has changed from 'Nice and easy' to 'This task is difficult, might need some help'", \
|
112
|
+
i.change_messages.to_sentence
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class CustomChangeMessagesTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class Item < ActiveRecord::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
class Person < ActiveRecord::Base
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
# schema needs to be loaded in the other test, so don't load it here a second time, unless this is run first or isolated
|
13
|
+
unless Item.connected? && Person.connected?
|
14
|
+
load_schema
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_schema_has_loaded_correctly
|
19
|
+
assert_nothing_raised do
|
20
|
+
Item.first
|
21
|
+
Person.first
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/test/database.yml
ADDED
data/test/schema.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :items, :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
t.string :description
|
5
|
+
t.integer :person_id
|
6
|
+
t.integer :category_id
|
7
|
+
t.date :due_on
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
create_table :people, :force => true do |t|
|
11
|
+
t.string :username
|
12
|
+
t.string :role
|
13
|
+
t.string :internal_calculation
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
create_table :categories, :force => true do |t|
|
17
|
+
t.string :name
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
|
7
|
+
def load_schema
|
8
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
9
|
+
# ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
10
|
+
|
11
|
+
db_adapter = ENV['DB']
|
12
|
+
|
13
|
+
# no db passed, try one of these fine config-free DBs before bombing.
|
14
|
+
db_adapter ||=
|
15
|
+
begin
|
16
|
+
require 'rubygems'
|
17
|
+
require 'sqlite'
|
18
|
+
'sqlite'
|
19
|
+
rescue LoadError
|
20
|
+
begin
|
21
|
+
require 'sqlite3'
|
22
|
+
'sqlite3'
|
23
|
+
rescue LoadError
|
24
|
+
puts "could not load sqlite for running the tests"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if db_adapter.nil?
|
29
|
+
raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
|
30
|
+
end
|
31
|
+
|
32
|
+
ActiveRecord::Base.establish_connection(config[db_adapter])
|
33
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
34
|
+
require File.dirname(__FILE__) + '/../rails/init.rb'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: custom_change_messages
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jeremy Olliver
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-26 00:00:00 +13:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 2.1.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sqlite3-ruby
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 21
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
- 5
|
50
|
+
version: 1.2.5
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Change history for ActiveRecord models in a customisable format, making user friendly logging for change history simple
|
54
|
+
email: jeremy.olliver@gmail.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- README
|
63
|
+
- Rakefile
|
64
|
+
- MIT-LICENSE
|
65
|
+
- lib/custom_change_messages.rb
|
66
|
+
- lib/custom_change_messages/active_record.rb
|
67
|
+
- test/active_record_test.rb
|
68
|
+
- test/custom_change_messages_test.rb
|
69
|
+
- test/database.yml
|
70
|
+
- test/schema.rb
|
71
|
+
- test/test_helper.rb
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/jeremyolliver/custom_change_messages
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
requirements: []
|
100
|
+
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.5.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Change history for ActiveRecord models
|
106
|
+
test_files:
|
107
|
+
- test/active_record_test.rb
|
108
|
+
- test/custom_change_messages_test.rb
|
109
|
+
- test/database.yml
|
110
|
+
- test/schema.rb
|
111
|
+
- test/test_helper.rb
|