historyable 0.0.1
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.
- checksums.yaml +15 -0
- checksums.yaml.gz.sig +0 -0
- data/lib/generators/historyable/USAGE +2 -0
- data/lib/generators/historyable/install_generator.rb +24 -0
- data/lib/generators/historyable/templates/migration.rb +16 -0
- data/lib/historyable/change.rb +4 -0
- data/lib/historyable/version.rb +3 -0
- data/lib/historyable.rb +102 -0
- data.tar.gz.sig +0 -0
- metadata +95 -0
- metadata.gz.sig +0 -0
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,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
|
data/lib/historyable.rb
ADDED
@@ -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
|