historyable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NWE3OTczNmRmZmQxY2RhMzc0OTk1MTJlY2JjMGUwY2E1YjlkMTJkNQ==
5
+ data.tar.gz: !binary |-
6
+ OTZhYWFhOWQwZGIzNGNhNWMwNTlhM2U4OTJlNWY3YjM5OGUwMmU4NA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YjUyZTBiZDRhMmRmYmVhZmYyOTU4ZjBjMGU5MDc1ODZhOTUwZjE3ZWIxY2Vm
10
+ ZDM5MGE5ZDhmOGIwZWY3OTY1MDUzZDM3YWQ4MzBlY2NiYzE3YWQ3YzkwZTMw
11
+ ZjJlMzNjOGNhMTQwNTM3OWU1YThhMmM2MmQ0YTYwNTYyNzJjY2M=
12
+ data.tar.gz: !binary |-
13
+ MWI1YzFmZmZiODZkNzg4ZDU2ZTRlM2RlN2NjYjk0YzY0NmI0NDc1M2Y5ZWEy
14
+ ZDU4MTRhZDZjMmNmMzEzZDJmNmUyYTU5NjllOWI4MDA3YzQ5Y2NkYmQ3NTUw
15
+ NThhYTczM2FiOWFmNjY3YWE3MTc2MzYxNmRjMmVlMTlmNTU5YWI=
checksums.yaml.gz.sig ADDED
Binary file
@@ -0,0 +1,2 @@
1
+ Description:
2
+ The historyable:install generator generates a migration creating a `changes` table in your database.
@@ -0,0 +1,24 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module Historyable
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ # Implement the required interface for Rails::Generators::Migration.
11
+ def self.next_migration_number(dirname)
12
+ if ActiveRecord::Base.timestamped_migrations
13
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
14
+ else
15
+ "%.3d" % (current_migration_number(dirname) + 1)
16
+ end
17
+ end
18
+
19
+ def create_migration_file
20
+ migration_template 'migration.rb', 'db/migrate/create_changes.rb'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ class CreateChanges < ActiveRecord::Migration
2
+ def up
3
+ create_table :changes do |t|
4
+ t.references :item, polymorphic: true
5
+ t.string :object_attribute
6
+ t.text :object_attribute_value
7
+ t.datetime :created_at
8
+ end
9
+
10
+ add_index :changes, [:item_type, :item_id]
11
+ end
12
+
13
+ def down
14
+ drop_table :changes
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ class Change < ActiveRecord::Base
2
+ belongs_to :historyable, polymorphic: true
3
+ serialize :object_attribute_value
4
+ end
@@ -0,0 +1,3 @@
1
+ module Historyable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,102 @@
1
+ require "historyable/version"
2
+
3
+ require "active_record"
4
+ require "historyable/change"
5
+
6
+ module Historyable
7
+ class Item < Struct.new(:attribute, :association_name); end
8
+
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ class_attribute :historyable_items, instance_writer: false
13
+ end
14
+
15
+
16
+ module ClassMethods
17
+
18
+ # @param attributes [Array, Symbol]
19
+ def has_history(*attributes)
20
+ self.historyable_items = attributes.map do |attribute|
21
+ attribute = attribute.to_sym
22
+ association_name = attribute.to_s.insert(-1, '_changes').to_sym
23
+
24
+ Historyable::Item.new(attribute, association_name)
25
+ end
26
+
27
+ # Associations
28
+ historyable_items.each do |historyable|
29
+ has_many historyable.association_name,
30
+ as: :item,
31
+ class_name: '::Change',
32
+ dependent: :destroy
33
+ end
34
+
35
+
36
+ # Instance methods
37
+ historyable_items.each do |historyable|
38
+
39
+ # raw_attribute_history
40
+ #
41
+ # @return [ActiveRecord::Relation]
42
+ define_method("raw_#{historyable.attribute.to_s}_history") do
43
+ send(historyable.association_name)
44
+ .where(object_attribute: historyable.attribute)
45
+ .order('created_at DESC')
46
+ .select(:object_attribute_value, :created_at)
47
+ end
48
+
49
+
50
+ # attribute_history
51
+ #
52
+ # @return [Array]
53
+ define_method("#{historyable.attribute.to_s}_history") do
54
+ unless instance_variable_get("@#{historyable.attribute.to_s}_history".to_sym)
55
+ array = []
56
+
57
+ records = send("raw_#{historyable.attribute}_history")
58
+ .pluck(:object_attribute_value, :created_at)
59
+ records.map do |attribute_value, created_at|
60
+ hash = HashWithIndifferentAccess.new
61
+ hash[:attribute_value] = attribute_value
62
+ hash[:changed_at] = created_at
63
+
64
+ array << hash
65
+ end
66
+
67
+ # Sets attribute_history cache
68
+ instance_variable_set("@#{historyable.attribute.to_s}_history".to_sym, array)
69
+ array
70
+ else
71
+ instance_variable_get("@#{historyable.attribute.to_s}_history".to_sym)
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ # Callbacks
78
+ around_save :save_changes
79
+ end
80
+ end
81
+
82
+
83
+ private
84
+
85
+ # Creates a Change record when an attribute marked as 'historyable' changes
86
+ def save_changes
87
+ changed_historyable_items = historyable_items.select do |historyable|
88
+ changed.include?(historyable.attribute.to_s)
89
+ end
90
+
91
+ yield # saves the records
92
+
93
+ changed_historyable_items.each do |historyable|
94
+ send(historyable.association_name).create(object_attribute: historyable.attribute,
95
+ object_attribute_value: send(historyable.attribute))
96
+ # Expires attribute_history cache
97
+ instance_variable_set("@#{historyable.attribute.to_s}_history".to_sym, nil)
98
+ end
99
+
100
+ true
101
+ end
102
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: historyable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Philippe Dionne
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - !binary |-
12
+ LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURmRENDQW1TZ0F3SUJB
13
+ Z0lCQVRBTkJna3Foa2lHOXcwQkFRVUZBREJDTVJRd0VnWURWUVFEREF0a2FX
14
+ OXUKYm1VdWNHaHBiREVWTUJNR0NnbVNKb21UOGl4a0FSa1dCV2R0WVdsc01S
15
+ TXdFUVlLQ1pJbWlaUHlMR1FCR1JZRApZMjl0TUI0WERURXpNRE13T1RFek1q
16
+ TXpOVm9YRFRFME1ETXdPVEV6TWpNek5Wb3dRakVVTUJJR0ExVUVBd3dMClpH
17
+ bHZibTVsTG5Cb2FXd3hGVEFUQmdvSmtpYUprL0lzWkFFWkZnVm5iV0ZwYkRF
18
+ VE1CRUdDZ21TSm9tVDhpeGsKQVJrV0EyTnZiVENDQVNJd0RRWUpLb1pJaHZj
19
+ TkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMdEdLMk5vRnlWWApzZUtsZkhi
20
+ OG51aEJ5OHJ3MW5QM0pWSFdveXFhbExzMHQzYXhVV2U2c0RDZ1FYQU9MM0Z0
21
+ a2ZZUFlseVg2WDRzCkZnZ2NTeVNVdDBQdkdkYXMweW0vbFcrc2ZHVDZnWERC
22
+ S2JQdmtXRk50cFhhSUo4RkxocW5KUjJtNTdiOFI2cGYKVk1CRGthOTVOODBY
23
+ dTlOUXJBZXNGK3dXL2M2WmlBT04yVkRzV2FiWkVmajE0Nnk3WnZ2aUI3cFpI
24
+ bFB6bkk0VwpHVmZPazBNQ2wwUTYwSnlrN1d3TmVjK05BOXJHN3ZFL2RXZEdP
25
+ S2Z4VTZaSm5DNmRyQzNrQnNCS2tSWnMrR1JoCjZYb0NBc3JLYlJ3Yi9aSTNB
26
+ MVMvSjl5dnEvTlExQi9VM0Npc0JGaHQrQ2Jkc3BlWFZVRHg1ZGZmRFZ4bnhk
27
+ by8KdzJSM3dKTXZEMk1DQXdFQUFhTjlNSHN3Q1FZRFZSMFRCQUl3QURBTEJn
28
+ TlZIUThFQkFNQ0JMQXdIUVlEVlIwTwpCQllFRkErNjlkR3h2RnRMeEorYUg4
29
+ bDRVTzl5eTg1M01DQUdBMVVkRVFRWk1CZUJGV1JwYjI1dVpTNXdhR2xzClFH
30
+ ZHRZV2xzTG1OdmJUQWdCZ05WSFJJRUdUQVhnUlZrYVc5dWJtVXVjR2hwYkVC
31
+ bmJXRnBiQzVqYjIwd0RRWUoKS29aSWh2Y05BUUVGQlFBRGdnRUJBRDdWcHV5
32
+ bTBWdm5YT3lkb0NCa3Yvdzh1MzJOamlndDNiRjNpL1A5MTEwOAphRHZPUlV5
33
+ bVlyUHhhQmUrQXNTSlVrSkIwTUh5d0pkTWM0TUYzWUlTZWxDdlVGR3phOExZ
34
+ dnZVSWd5VktGb20rClROOFdDUFpMbzRtWWFZbzRzU3RrRi9HNXY4STNydVpP
35
+ YnI3by9mMjB4RzVyOEU0TkQyR0VHVGVGSmhncE1jSE8KSXIxdVluL0xMZUdH
36
+ NWcyRUFLQ2RZeTJYb29odGNTUFlBcGJlRlFnV09HS29pb1FWUkNERzNjSG1h
37
+ a2ZWQVY1TQpEdU5senZqaFd0UER3RTVtWU81eDVYcXVXUXVFTnc3OHVydDFh
38
+ aW9OckllMC8xNWRIcERvSUVESUxhNnpVNDZCClhEdHAxWXhkZVZHSUJ1Tm9Q
39
+ MXZqRFN2TktZajBwTWpSQUVQcnFLMzlqS0U9Ci0tLS0tRU5EIENFUlRJRklD
40
+ QVRFLS0tLS0K
41
+ date: 2013-08-21 00:00:00.000000000 Z
42
+ dependencies:
43
+ - !ruby/object:Gem::Dependency
44
+ prerelease: false
45
+ name: active_record
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: 3.0.0
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: 3.0.0
56
+ type: :runtime
57
+ description: Tracks model attributes changes.
58
+ email:
59
+ - philippe.dionne@hooktstudios.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/generators/historyable/USAGE
65
+ - lib/generators/historyable/install_generator.rb
66
+ - lib/generators/historyable/templates/migration.rb
67
+ - lib/historyable.rb
68
+ - lib/historyable/change.rb
69
+ - lib/historyable/version.rb
70
+ homepage: https://github.com/hooktstudios/historyable
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project: ! '[none]'
90
+ rubygems_version: 2.0.3
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Tracks model attributes changes.
94
+ test_files: []
95
+ has_rdoc:
metadata.gz.sig ADDED
Binary file