model_history 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/lib/generators/model_history/migration/migration_generator.rb +31 -0
- data/lib/generators/model_history/migration/templates/active_record/migration.rb +33 -0
- data/lib/model_history.rb +3 -0
- data/lib/model_history/model_history_mixin.rb +142 -0
- data/lib/model_history/model_history_record.rb +71 -0
- data/lib/model_history/version.rb +3 -0
- data/model_history.gemspec +28 -0
- data/spec/fake_app.rb +40 -0
- data/spec/models/user_spec.rb +35 -0
- data/spec/spec_helper.rb +18 -0
- metadata +185 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 patorash
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# ModelHistory
|
2
|
+
|
3
|
+
Model History is a simple gem that allows you to keep track of changes to specific fields in your Rails models using the ActiveRecord::Dirty module.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'model_history'
|
10
|
+
|
11
|
+
Install it using Bundler:
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Generate the Model History migration and migrate your database
|
16
|
+
|
17
|
+
$ rails generate model_history:migration
|
18
|
+
$ rake db:migrate
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
```Ruby
|
23
|
+
class Widget < ActiveRecord::Base
|
24
|
+
has_model_history :name, :price, :creator => proc{ User.current_user }
|
25
|
+
attr_accessible :name, :price
|
26
|
+
end
|
27
|
+
|
28
|
+
widget = Widget.last
|
29
|
+
widget.name # => "Box"
|
30
|
+
widget.name = "Heart Shaped Box"
|
31
|
+
widget.save
|
32
|
+
widget.model_history_records # => returns all changes to the widget
|
33
|
+
|
34
|
+
model_history = widget.model_history_records.last
|
35
|
+
model_history.old_value # => "Box"
|
36
|
+
model_history.new_value # => "Heart Shaped Box"
|
37
|
+
|
38
|
+
user = User.find(123)
|
39
|
+
widget.model_history_records.created_by(user)
|
40
|
+
# => returns all changes to the widget performed by the specified user
|
41
|
+
|
42
|
+
class User < ActiveRecord::Base
|
43
|
+
creates_model_history
|
44
|
+
end
|
45
|
+
|
46
|
+
user = User.find(123)
|
47
|
+
user.model_history_records
|
48
|
+
# => returns changes made by the specified user
|
49
|
+
```
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
|
3
|
+
module ModelHistory
|
4
|
+
class MigrationGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
desc "Generates migration for ModelHistoryRecord model"
|
8
|
+
|
9
|
+
def self.orm
|
10
|
+
Rails::Generators.options[:rails][:orm]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.source_root
|
14
|
+
File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.orm_has_migration?
|
18
|
+
[:active_record].include? orm
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.next_migration_number(path)
|
22
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_migration_file
|
26
|
+
if self.class.orm_has_migration?
|
27
|
+
migration_template 'migration.rb', 'db/migrate/create_model_history_records'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class CreateModelHistoryRecords < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :model_history_records do |t|
|
4
|
+
t.integer :creator_id
|
5
|
+
t.string :creator_type, :limit => 64
|
6
|
+
t.integer :model_id
|
7
|
+
t.string :model_type, :limit => 64
|
8
|
+
t.string :column_name, :limit => 64
|
9
|
+
t.string :column_type, :limit => 16 # :string, :text, :integer, :decimal, :float, :datetime, :boolean
|
10
|
+
t.string :old_value, :limit => 128
|
11
|
+
t.string :new_value, :limit => 128
|
12
|
+
|
13
|
+
t.datetime :created_at
|
14
|
+
t.datetime :revised_created_at
|
15
|
+
t.datetime :updated_at
|
16
|
+
t.datetime :deleted_at
|
17
|
+
end
|
18
|
+
add_index :model_history_records, [:creator_id, :creator_type]
|
19
|
+
add_index :model_history_records, [:model_id, :model_type]
|
20
|
+
add_index :model_history_records, [:created_at, :revised_created_at], :name => "index_created_at"
|
21
|
+
add_index :model_history_records, [:deleted_at, :created_at, :revised_created_at], :name => "index_deleted_at_created_at"
|
22
|
+
add_index :model_history_records, [:model_type, :column_name, :deleted_at], :name => "index_obj_type_column_deleted_at"
|
23
|
+
add_index :model_history_records, [:model_type, :column_name, :deleted_at, :created_at, :revised_created_at], :name => "index_obj_type_column_deleted_at_created_at"
|
24
|
+
|
25
|
+
add_index :model_history_records, :old_value, :name => "index_old_value"
|
26
|
+
add_index :model_history_records, :new_value, :name => "index_new_value"
|
27
|
+
add_index :model_history_records, [:old_value, :new_value], :name => "index_old_value_new_value"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.down
|
31
|
+
drop_table :model_history_records
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module ModelHistory
|
2
|
+
|
3
|
+
module Mixin
|
4
|
+
|
5
|
+
class CreatorProcError < StandardError ; end
|
6
|
+
|
7
|
+
def self.included base
|
8
|
+
base.class_eval do
|
9
|
+
extend ClassMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# call the model_history class method on models with fields that you want to track changes on.
|
16
|
+
# example usage:
|
17
|
+
# class User < ActiveRecord::Base
|
18
|
+
# has_model_history :email, :first_name, :last_name
|
19
|
+
# end
|
20
|
+
|
21
|
+
# pass an optional proc to assign a creator to the model_history object
|
22
|
+
# example usage:
|
23
|
+
# class User < ActiveRecord::Base
|
24
|
+
# has_model_history :email, :first_name, :last_name, :creator => proc { User.current_user }
|
25
|
+
# end
|
26
|
+
|
27
|
+
def has_model_history *args
|
28
|
+
# Mix in the module, but ensure to do so just once.
|
29
|
+
metaclass = (class << self; self; end)
|
30
|
+
return if metaclass.included_modules.include?(ModelHistory::Mixin::ObjectInstanceMethods)
|
31
|
+
|
32
|
+
has_many :model_history_records, :as => :model, :dependent => :destroy
|
33
|
+
attr_accessor :model_history_changes, :initialize_model_history
|
34
|
+
cattr_accessor :model_history_columns
|
35
|
+
|
36
|
+
|
37
|
+
self.model_history_columns ||= []
|
38
|
+
|
39
|
+
if args.present?
|
40
|
+
|
41
|
+
before_save :set_model_history_changes
|
42
|
+
after_save :save_model_history
|
43
|
+
|
44
|
+
args.each do |arg|
|
45
|
+
if [String,Symbol].include?(arg.class)
|
46
|
+
arg = arg.to_sym
|
47
|
+
self.model_history_columns << arg unless self.model_history_columns.include?(arg)
|
48
|
+
define_method "creator_for_model_history" do end
|
49
|
+
elsif arg.is_a?(Hash)
|
50
|
+
creator_proc = arg.delete(:creator)
|
51
|
+
send :define_method, "creator_for_model_history" do
|
52
|
+
begin
|
53
|
+
creator_proc.is_a?(Proc) ? creator_proc.call : nil
|
54
|
+
rescue
|
55
|
+
raise ModelHistory::Mixin::CreatorProcError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
include ModelHistory::Mixin::ObjectInstanceMethods
|
61
|
+
end
|
62
|
+
end # has_model_history
|
63
|
+
|
64
|
+
def creates_model_history
|
65
|
+
# Mix in the module, but ensure to do so just once.
|
66
|
+
metaclass = (class << self; self; end)
|
67
|
+
return if metaclass.included_modules.include?(ModelHistory::Mixin::CreatorInstanceMethods)
|
68
|
+
|
69
|
+
has_many :model_history_records, :as => :creator
|
70
|
+
|
71
|
+
include ModelHistory::Mixin::CreatorInstanceMethods
|
72
|
+
end # creates_model_history
|
73
|
+
end # ClassMethods
|
74
|
+
|
75
|
+
module ObjectInstanceMethods
|
76
|
+
|
77
|
+
def set_model_history_changes
|
78
|
+
return true unless self.new_record? || self.changed?
|
79
|
+
|
80
|
+
self.model_history_changes = self.class.model_history_columns.inject({}) do |changes_hash, column_name|
|
81
|
+
changes_hash[column_name] = self.send("#{column_name}_change") if self.send("#{column_name}_changed?")
|
82
|
+
changes_hash[column_name] ||= [nil, self.send(column_name)] if self.new_record? && self.send(column_name).present?
|
83
|
+
changes_hash
|
84
|
+
end
|
85
|
+
|
86
|
+
self.initialize_model_history = self.new_record?
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
def save_model_history
|
91
|
+
return true unless self.model_history_changes.present?
|
92
|
+
self.model_history_changes.each do |column_name,vals|
|
93
|
+
add_model_history_record column_name, vals[0], vals[1], :creator => self.creator_for_model_history
|
94
|
+
end
|
95
|
+
self.model_history_changes = nil
|
96
|
+
true
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_model_history_record column_name, old_value, new_value, options={}
|
100
|
+
creator = options[:creator] || self.creator_for_model_history
|
101
|
+
|
102
|
+
dhr_attributes = {
|
103
|
+
:model => self,
|
104
|
+
:column_name => column_name,
|
105
|
+
:column_type => self.class.columns_hash[column_name.to_s].type,
|
106
|
+
:old_value => old_value,
|
107
|
+
:new_value => new_value,
|
108
|
+
:creator => creator
|
109
|
+
}
|
110
|
+
|
111
|
+
dhr = ModelHistoryRecord.new(dhr_attributes)
|
112
|
+
|
113
|
+
# attributes for manual updates
|
114
|
+
[:revised_created_at, :performing_manual_update].each do |attribute|
|
115
|
+
dhr.send("#{attribute}=", options[attribute]) if options[attribute]
|
116
|
+
end
|
117
|
+
|
118
|
+
self.model_history_records << dhr
|
119
|
+
end
|
120
|
+
|
121
|
+
def history_for_column column, options={}
|
122
|
+
options[:sort] = true if options[:sort].blank?
|
123
|
+
|
124
|
+
records = model_history_records.for_column(column)
|
125
|
+
records = records.send(*options[:scope]) if options[:scope]
|
126
|
+
records = records.order_asc if options[:sort]
|
127
|
+
|
128
|
+
options[:return_objects] ? records : records.map { |s| s.new_value }
|
129
|
+
end
|
130
|
+
|
131
|
+
end # ObjectInstanceMethods
|
132
|
+
|
133
|
+
module CreatorInstanceMethods
|
134
|
+
|
135
|
+
end # CreatorInstanceMethods
|
136
|
+
|
137
|
+
end # Mixin
|
138
|
+
|
139
|
+
end # ModelHistory
|
140
|
+
|
141
|
+
|
142
|
+
ActiveRecord::Base.send :include, ModelHistory::Mixin
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
class ModelHistoryRecord < ActiveRecord::Base
|
4
|
+
belongs_to :creator, :polymorphic => true
|
5
|
+
belongs_to :model, :polymorphic => true
|
6
|
+
|
7
|
+
validates_presence_of :model_type, :model_id, :column_name, :column_type, :new_value
|
8
|
+
|
9
|
+
scope :created_by, lambda { |creator| where(["#{table_name}.creator_id = ? AND #{table_name}.creator_type = ?", creator.id, creator.class.name]) }
|
10
|
+
scope :not_created_by, lambda { |non_creator| where(["#{table_name}.creator_id <> ? OR #{table_name}.creator_type <> ?", non_creator.id, non_creator.class.name]) }
|
11
|
+
scope :for_model_type, lambda { |model_type| where(model_type: model_type.to_s.classify) }
|
12
|
+
scope :for_column, lambda { |column| where(column_name: column.to_s) }
|
13
|
+
scope :created_in_range, lambda { |range| created_at_gte(range.first).created_at_lte(range.last) }
|
14
|
+
scope :created_at_gte, lambda { |date| created_at_lte_or_gte(date,"gte") }
|
15
|
+
scope :created_at_lte, lambda { |date| created_at_lte_or_gte(date,"lte") }
|
16
|
+
scope :created_at_lte_or_gte, lambda { |date, lte_or_gte|
|
17
|
+
lte_or_gte = lte_or_gte.to_s == "lte" ? "<=" : ">="
|
18
|
+
where("((#{table_name}.revised_created_at is NULL OR #{table_name}.revised_created_at = '') AND #{table_name}.created_at #{lte_or_gte} ?) " +
|
19
|
+
" OR #{table_name}.revised_created_at #{lte_or_gte} ?", date, date)
|
20
|
+
}
|
21
|
+
|
22
|
+
scope :order_asc, lambda { order_by_action_timestamp("ASC") }
|
23
|
+
scope :order_desc, lambda { order_by_action_timestamp("DESC") }
|
24
|
+
scope :order_by_action_timestamp, lambda { |asc_or_desc|
|
25
|
+
order("CASE WHEN (#{table_name}.revised_created_at IS NULL OR #{table_name}.revised_created_at = '') then #{table_name}.created_at else #{table_name}.revised_created_at END #{asc_or_desc}")
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
attr_accessible :model, :model_id, :model_type,
|
30
|
+
:column_name, :column_type, :old_value, :new_value,
|
31
|
+
:creator, :creator_id, :creator_type, :revised_created_at
|
32
|
+
|
33
|
+
attr_accessor :performing_manual_update
|
34
|
+
|
35
|
+
|
36
|
+
[:new_value, :old_value].each do |attribute|
|
37
|
+
define_method "#{attribute}" do
|
38
|
+
val_to_col_type(attribute)
|
39
|
+
end
|
40
|
+
define_method "#{attribute}=" do |val|
|
41
|
+
self[attribute] = val.nil? ? nil : val.to_s
|
42
|
+
instance_variable_set "@#{attribute}", val
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def action_timestamp
|
47
|
+
# use revised_created_at field to update the timestamp for
|
48
|
+
# the dirty history action while retaining data integrity
|
49
|
+
self[:revised_created_at] || self[:created_at]
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def val_to_col_type attribute
|
55
|
+
val_as_string = self[attribute]
|
56
|
+
return nil if val_as_string.nil?
|
57
|
+
case self[:column_type].to_sym
|
58
|
+
when :integer, :boolean
|
59
|
+
val_as_string.to_i
|
60
|
+
when :decimal, :float
|
61
|
+
val_as_string.to_f
|
62
|
+
when :datetime
|
63
|
+
Time.parse val_as_string
|
64
|
+
when :date
|
65
|
+
Date.parse val_as_string
|
66
|
+
else # :string, :text
|
67
|
+
val_as_string
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'model_history/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'model_history'
|
8
|
+
spec.version = ModelHistory::VERSION
|
9
|
+
spec.authors = ['patorash']
|
10
|
+
spec.email = ['chariderpato@gmail.com']
|
11
|
+
spec.description = %q{Model History is a simple gem that allows you to keep track of changes to specific fields in your Rails models using the ActiveRecord::Dirty module.}
|
12
|
+
spec.summary = %q{Model History is a simple gem that allows you to keep track of changes to specific fields in your Rails models using the ActiveRecord::Dirty module.}
|
13
|
+
spec.homepage = 'https://github.com/patorash/model_history'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
spec.add_development_dependency 'rspec-rails'
|
25
|
+
spec.add_development_dependency 'activerecord'
|
26
|
+
spec.add_development_dependency 'sqlite3'
|
27
|
+
spec.add_dependency 'rails', '>= 3.2.11'
|
28
|
+
end
|
data/spec/fake_app.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'active_record'
|
3
|
+
require 'action_controller/railtie'
|
4
|
+
require 'action_view/helpers'
|
5
|
+
require 'model_history'
|
6
|
+
|
7
|
+
# database
|
8
|
+
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
9
|
+
ActiveRecord::Base.establish_connection('test')
|
10
|
+
|
11
|
+
# config
|
12
|
+
app = Class.new(Rails::Application)
|
13
|
+
app.config.secret_token = '3b7cd727ee24e8444053437c36cc66c4'
|
14
|
+
app.config.session_store :cookie_store, :key => '_myapp_session'
|
15
|
+
app.config.active_support.deprecation = :log
|
16
|
+
app.initialize!
|
17
|
+
|
18
|
+
# routes
|
19
|
+
app.routes.draw do
|
20
|
+
resources :users
|
21
|
+
end
|
22
|
+
|
23
|
+
# models
|
24
|
+
class User < ActiveRecord::Base
|
25
|
+
has_model_history :name, :age
|
26
|
+
validates :name, :presence => true
|
27
|
+
end
|
28
|
+
|
29
|
+
# controllers
|
30
|
+
class ApplicationController < ActionController::Base; end
|
31
|
+
|
32
|
+
# helpers
|
33
|
+
Object.const_set(:ApplicationHelper, Module.new)
|
34
|
+
|
35
|
+
#migrations
|
36
|
+
class CreateAllTables < ActiveRecord::Migration
|
37
|
+
def self.up
|
38
|
+
create_table(:users) {|t| t.string :name; t.integer :age}
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe User do
|
5
|
+
describe "Check history" do
|
6
|
+
context "name change" do
|
7
|
+
before do
|
8
|
+
@user = User.create!(:name => 'Makunouchi', :age => 22)
|
9
|
+
@user.update_attributes!(:name => 'Sendo')
|
10
|
+
end
|
11
|
+
it "Get user history" do
|
12
|
+
history = @user.model_history_records.last
|
13
|
+
history.model_type.should == 'User'
|
14
|
+
history.column_name.should == 'name'
|
15
|
+
history.column_type.should == 'string'
|
16
|
+
history.old_value.should == 'Makunouchi'
|
17
|
+
history.new_value.should == 'Sendo'
|
18
|
+
end
|
19
|
+
it "#history_for_column" do
|
20
|
+
histories = @user.history_for_column :name
|
21
|
+
histories.should have(2).items
|
22
|
+
histories.should == ['Makunouchi', 'Sendo']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "callback methods" do
|
27
|
+
it "call add_model_history_record" do
|
28
|
+
user = User.new(:name => "Makunouchi", :age => 22)
|
29
|
+
user.should_receive(:set_model_history_changes)
|
30
|
+
user.should_receive(:save_model_history)
|
31
|
+
user.save!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
# Requires supporting files with custom matchers and macros, etc,
|
6
|
+
# in ./support/ and its subdirectories.
|
7
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
8
|
+
require File.join(File.dirname(__FILE__), 'fake_app')
|
9
|
+
|
10
|
+
require 'rspec/rails'
|
11
|
+
require 'generators/model_history/migration/templates/active_record/migration'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.before :all do
|
15
|
+
CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'users'
|
16
|
+
CreateModelHistoryRecords.up unless ActiveRecord::Base.connection.table_exists? 'model_history_records'
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: model_history
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- patorash
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec-rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: activerecord
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sqlite3
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rails
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 3.2.11
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 3.2.11
|
126
|
+
description: Model History is a simple gem that allows you to keep track of changes
|
127
|
+
to specific fields in your Rails models using the ActiveRecord::Dirty module.
|
128
|
+
email:
|
129
|
+
- chariderpato@gmail.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- .gitignore
|
135
|
+
- .rspec
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE.txt
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- lib/generators/model_history/migration/migration_generator.rb
|
141
|
+
- lib/generators/model_history/migration/templates/active_record/migration.rb
|
142
|
+
- lib/model_history.rb
|
143
|
+
- lib/model_history/model_history_mixin.rb
|
144
|
+
- lib/model_history/model_history_record.rb
|
145
|
+
- lib/model_history/version.rb
|
146
|
+
- model_history.gemspec
|
147
|
+
- spec/fake_app.rb
|
148
|
+
- spec/models/user_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage: https://github.com/patorash/model_history
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
segments:
|
164
|
+
- 0
|
165
|
+
hash: 1898891071957235163
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ! '>='
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
segments:
|
173
|
+
- 0
|
174
|
+
hash: 1898891071957235163
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 1.8.25
|
178
|
+
signing_key:
|
179
|
+
specification_version: 3
|
180
|
+
summary: Model History is a simple gem that allows you to keep track of changes to
|
181
|
+
specific fields in your Rails models using the ActiveRecord::Dirty module.
|
182
|
+
test_files:
|
183
|
+
- spec/fake_app.rb
|
184
|
+
- spec/models/user_spec.rb
|
185
|
+
- spec/spec_helper.rb
|