model_history 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .idea/
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ log/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in model_history.gemspec
4
+ gemspec
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,3 @@
1
+ require "model_history/version"
2
+ autoload :ModelHistoryRecord, 'model_history/model_history_record'
3
+ require 'model_history/model_history_mixin'
@@ -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,3 @@
1
+ module ModelHistory
2
+ VERSION = "0.1.0"
3
+ 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
@@ -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