paper_trail_without_deprecated 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +21 -0
  5. data/CHANGELOG.md +68 -0
  6. data/Gemfile +2 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +979 -0
  9. data/Rakefile +18 -0
  10. data/gemfiles/3.0.gemfile +31 -0
  11. data/lib/generators/paper_trail/USAGE +2 -0
  12. data/lib/generators/paper_trail/install_generator.rb +23 -0
  13. data/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb +9 -0
  14. data/lib/generators/paper_trail/templates/create_versions.rb +18 -0
  15. data/lib/paper_trail.rb +115 -0
  16. data/lib/paper_trail/cleaner.rb +34 -0
  17. data/lib/paper_trail/config.rb +14 -0
  18. data/lib/paper_trail/frameworks/cucumber.rb +31 -0
  19. data/lib/paper_trail/frameworks/rails.rb +79 -0
  20. data/lib/paper_trail/frameworks/rspec.rb +24 -0
  21. data/lib/paper_trail/frameworks/rspec/extensions.rb +20 -0
  22. data/lib/paper_trail/frameworks/sinatra.rb +31 -0
  23. data/lib/paper_trail/has_paper_trail.rb +308 -0
  24. data/lib/paper_trail/serializers/json.rb +17 -0
  25. data/lib/paper_trail/serializers/yaml.rb +17 -0
  26. data/lib/paper_trail/version.rb +200 -0
  27. data/lib/paper_trail/version_number.rb +3 -0
  28. data/paper_trail.gemspec +36 -0
  29. data/spec/models/widget_spec.rb +13 -0
  30. data/spec/paper_trail_spec.rb +47 -0
  31. data/spec/spec_helper.rb +41 -0
  32. data/test/custom_json_serializer.rb +13 -0
  33. data/test/dummy/Rakefile +7 -0
  34. data/test/dummy/app/controllers/application_controller.rb +17 -0
  35. data/test/dummy/app/controllers/test_controller.rb +5 -0
  36. data/test/dummy/app/controllers/widgets_controller.rb +31 -0
  37. data/test/dummy/app/helpers/application_helper.rb +2 -0
  38. data/test/dummy/app/models/animal.rb +4 -0
  39. data/test/dummy/app/models/article.rb +16 -0
  40. data/test/dummy/app/models/authorship.rb +5 -0
  41. data/test/dummy/app/models/book.rb +5 -0
  42. data/test/dummy/app/models/cat.rb +2 -0
  43. data/test/dummy/app/models/document.rb +4 -0
  44. data/test/dummy/app/models/dog.rb +2 -0
  45. data/test/dummy/app/models/elephant.rb +3 -0
  46. data/test/dummy/app/models/fluxor.rb +3 -0
  47. data/test/dummy/app/models/foo_widget.rb +2 -0
  48. data/test/dummy/app/models/legacy_widget.rb +4 -0
  49. data/test/dummy/app/models/person.rb +28 -0
  50. data/test/dummy/app/models/post.rb +4 -0
  51. data/test/dummy/app/models/protected_widget.rb +3 -0
  52. data/test/dummy/app/models/song.rb +12 -0
  53. data/test/dummy/app/models/translation.rb +4 -0
  54. data/test/dummy/app/models/widget.rb +10 -0
  55. data/test/dummy/app/models/wotsit.rb +4 -0
  56. data/test/dummy/app/versions/post_version.rb +3 -0
  57. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  58. data/test/dummy/config.ru +4 -0
  59. data/test/dummy/config/application.rb +63 -0
  60. data/test/dummy/config/boot.rb +10 -0
  61. data/test/dummy/config/database.yml +22 -0
  62. data/test/dummy/config/environment.rb +5 -0
  63. data/test/dummy/config/environments/development.rb +40 -0
  64. data/test/dummy/config/environments/production.rb +73 -0
  65. data/test/dummy/config/environments/test.rb +37 -0
  66. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  67. data/test/dummy/config/initializers/inflections.rb +10 -0
  68. data/test/dummy/config/initializers/mime_types.rb +5 -0
  69. data/test/dummy/config/initializers/paper_trail.rb +5 -0
  70. data/test/dummy/config/initializers/secret_token.rb +7 -0
  71. data/test/dummy/config/initializers/session_store.rb +8 -0
  72. data/test/dummy/config/locales/en.yml +5 -0
  73. data/test/dummy/config/routes.rb +3 -0
  74. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +136 -0
  75. data/test/dummy/db/schema.rb +101 -0
  76. data/test/dummy/public/404.html +26 -0
  77. data/test/dummy/public/422.html +26 -0
  78. data/test/dummy/public/500.html +26 -0
  79. data/test/dummy/public/favicon.ico +0 -0
  80. data/test/dummy/public/javascripts/application.js +2 -0
  81. data/test/dummy/public/javascripts/controls.js +965 -0
  82. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  83. data/test/dummy/public/javascripts/effects.js +1123 -0
  84. data/test/dummy/public/javascripts/prototype.js +6001 -0
  85. data/test/dummy/public/javascripts/rails.js +175 -0
  86. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  87. data/test/dummy/script/rails +6 -0
  88. data/test/functional/controller_test.rb +90 -0
  89. data/test/functional/modular_sinatra_test.rb +44 -0
  90. data/test/functional/sinatra_test.rb +45 -0
  91. data/test/functional/thread_safety_test.rb +26 -0
  92. data/test/paper_trail_test.rb +27 -0
  93. data/test/test_helper.rb +40 -0
  94. data/test/unit/cleaner_test.rb +143 -0
  95. data/test/unit/inheritance_column_test.rb +43 -0
  96. data/test/unit/model_test.rb +1314 -0
  97. data/test/unit/protected_attrs_test.rb +46 -0
  98. data/test/unit/serializer_test.rb +117 -0
  99. data/test/unit/serializers/json_test.rb +40 -0
  100. data/test/unit/serializers/mixin_json_test.rb +36 -0
  101. data/test/unit/serializers/mixin_yaml_test.rb +49 -0
  102. data/test/unit/serializers/yaml_test.rb +40 -0
  103. data/test/unit/timestamp_test.rb +44 -0
  104. data/test/unit/version_test.rb +74 -0
  105. metadata +286 -0
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ desc 'Run tests on PaperTrail with Test::Unit.'
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'lib'
8
+ t.libs << 'test'
9
+ t.pattern = 'test/**/*_test.rb'
10
+ t.verbose = false
11
+ end
12
+
13
+ require 'rspec/core/rake_task'
14
+ desc 'Run PaperTrail specs for the RSpec helper.'
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ desc 'Default: run all available test suites'
18
+ task :default => [:test, :spec]
@@ -0,0 +1,31 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~> 3.0'
4
+
5
+ group :development, :test do
6
+ gem 'rake'
7
+ gem 'shoulda', '~> 3.5'
8
+ gem 'ffaker', '>= 1.15'
9
+
10
+ # Testing of Rails
11
+ gem 'railties', '~> 3.0'
12
+
13
+ # Testing of Sinatra
14
+ gem 'sinatra', '~> 1.0'
15
+ gem 'rack-test', '>= 0.6'
16
+
17
+ # Use sqlite3 gem for regular Ruby
18
+ gem 'sqlite3', '~> 1.2', :platform => :ruby
19
+
20
+ # RSpec testing
21
+ gem 'rspec-rails', '~> 2.14'
22
+
23
+ platforms :jruby, :ruby_18 do
24
+ # shoulda-matchers > 2.0 is not compatible with Ruby18.
25
+ # Since we can't specify difference between JRuby 18/19, we need to use shoulda-matchers 1.5 for all JRuby testing.
26
+ gem 'shoulda-matchers', '~> 1.5'
27
+ end
28
+
29
+ # Use jRuby's sqlite3 adapter for jRuby
30
+ gem 'activerecord-jdbcsqlite3-adapter', '~> 1.2.9', :platform => :jruby
31
+ end
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Generates (but does not run) a migration to add a versions table.
@@ -0,0 +1,23 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module PaperTrail
6
+ class InstallGenerator < ::Rails::Generators::Base
7
+ include ::Rails::Generators::Migration
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+ class_option :with_changes, :type => :boolean, :default => false, :desc => "Store changeset (diff) with each version"
11
+
12
+ desc 'Generates (but does not run) a migration to add a versions table.'
13
+
14
+ def create_migration_file
15
+ migration_template 'create_versions.rb', 'db/migrate/create_versions.rb'
16
+ migration_template 'add_object_changes_column_to_versions.rb', 'db/migrate/add_object_changes_column_to_versions.rb' if options.with_changes?
17
+ end
18
+
19
+ def self.next_migration_number(dirname)
20
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ class AddObjectChangesColumnToVersions < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :versions, :object_changes, :text
4
+ end
5
+
6
+ def self.down
7
+ remove_column :versions, :object_changes
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ class CreateVersions < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :versions do |t|
4
+ t.string :item_type, :null => false
5
+ t.integer :item_id, :null => false
6
+ t.string :event, :null => false
7
+ t.string :whodunnit
8
+ t.text :object
9
+ t.datetime :created_at
10
+ end
11
+ add_index :versions, [:item_type, :item_id]
12
+ end
13
+
14
+ def self.down
15
+ remove_index :versions, [:item_type, :item_id]
16
+ drop_table :versions
17
+ end
18
+ end
@@ -0,0 +1,115 @@
1
+ require 'paper_trail/config'
2
+ require 'paper_trail/has_paper_trail'
3
+ require 'paper_trail/cleaner'
4
+
5
+ # Require all frameworks and serializers
6
+ Dir[File.join(File.dirname(__FILE__), 'paper_trail', 'frameworks', '*.rb')].each { |file| require file }
7
+ Dir[File.join(File.dirname(__FILE__), 'paper_trail', 'serializers', '*.rb')].each { |file| require file }
8
+
9
+ # PaperTrail's module methods can be called in both models and controllers.
10
+ module PaperTrail
11
+ extend PaperTrail::Cleaner
12
+
13
+ # Switches PaperTrail on or off.
14
+ def self.enabled=(value)
15
+ PaperTrail.config.enabled = value
16
+ end
17
+
18
+ # Returns `true` if PaperTrail is on, `false` otherwise.
19
+ # PaperTrail is enabled by default.
20
+ def self.enabled?
21
+ !!PaperTrail.config.enabled
22
+ end
23
+
24
+ # Returns `true` if PaperTrail is enabled for the request, `false` otherwise.
25
+ #
26
+ # See `PaperTrail::Controller#paper_trail_enabled_for_controller`.
27
+ def self.enabled_for_controller?
28
+ !!paper_trail_store[:request_enabled_for_controller]
29
+ end
30
+
31
+ # Sets whether PaperTrail is enabled or disabled for the current request.
32
+ def self.enabled_for_controller=(value)
33
+ paper_trail_store[:request_enabled_for_controller] = value
34
+ end
35
+
36
+ # Set the field which records when a version was created.
37
+ def self.timestamp_field=(field_name)
38
+ PaperTrail.config.timestamp_field = field_name
39
+ end
40
+
41
+ # Returns the field which records when a version was created.
42
+ def self.timestamp_field
43
+ PaperTrail.config.timestamp_field
44
+ end
45
+
46
+ # Returns who is reponsible for any changes that occur.
47
+ def self.whodunnit
48
+ paper_trail_store[:whodunnit]
49
+ end
50
+
51
+ # Sets who is responsible for any changes that occur.
52
+ # You would normally use this in a migration or on the console,
53
+ # when working with models directly. In a controller it is set
54
+ # automatically to the `current_user`.
55
+ def self.whodunnit=(value)
56
+ paper_trail_store[:whodunnit] = value
57
+ end
58
+
59
+ # Returns any information from the controller that you want
60
+ # PaperTrail to store.
61
+ #
62
+ # See `PaperTrail::Controller#info_for_paper_trail`.
63
+ def self.controller_info
64
+ paper_trail_store[:controller_info]
65
+ end
66
+
67
+ # Sets any information from the controller that you want PaperTrail
68
+ # to store. By default this is set automatically by a before filter.
69
+ def self.controller_info=(value)
70
+ paper_trail_store[:controller_info] = value
71
+ end
72
+
73
+ # Getter and Setter for PaperTrail Serializer
74
+ def self.serializer=(value)
75
+ PaperTrail.config.serializer = value
76
+ end
77
+
78
+ def self.serializer
79
+ PaperTrail.config.serializer
80
+ end
81
+
82
+ def self.active_record_protected_attributes?
83
+ @active_record_protected_attributes ||= ActiveRecord::VERSION::STRING.to_f < 4.0 || defined?(ProtectedAttributes)
84
+ end
85
+
86
+ private
87
+
88
+ # Thread-safe hash to hold PaperTrail's data.
89
+ # Initializing with needed default values.
90
+ def self.paper_trail_store
91
+ Thread.current[:paper_trail] ||= { :request_enabled_for_controller => true }
92
+ end
93
+
94
+ # Returns PaperTrail's configuration object.
95
+ def self.config
96
+ @@config ||= PaperTrail::Config.instance
97
+ end
98
+
99
+ def self.configure
100
+ yield config
101
+ end
102
+
103
+ end
104
+
105
+ require 'paper_trail/version'
106
+
107
+ ActiveSupport.on_load(:active_record) do
108
+ include PaperTrail::Model
109
+ end
110
+
111
+ if defined?(ActionController)
112
+ ActiveSupport.on_load(:action_controller) do
113
+ include PaperTrail::Rails::Controller
114
+ end
115
+ end
@@ -0,0 +1,34 @@
1
+ module PaperTrail
2
+ module Cleaner
3
+ # Destroys all but the most recent version(s) for items on a given date (or on all dates). Useful for deleting drafts.
4
+ #
5
+ # Options:
6
+ # :keeping An `integer` indicating the number of versions to be kept for each item per date.
7
+ # Defaults to `1`.
8
+ # :date Should either be a `Date` object specifying which date to destroy versions for or `:all`,
9
+ # which will specify that all dates should be cleaned. Defaults to `:all`.
10
+ # :item_id The `id` for the item to be cleaned on, or `nil`, which causes all items to be cleaned.
11
+ # Defaults to `nil`.
12
+ def clean_versions!(options = {})
13
+ options = {:keeping => 1, :date => :all}.merge(options)
14
+ gather_versions(options[:item_id], options[:date]).each do |item_id, versions|
15
+ versions.group_by { |v| v.created_at.to_date }.each do |date, versions| # now group the versions by date and iterate through those
16
+ versions.pop(options[:keeping]) # remove the number of versions we wish to keep from the collection of versions prior to destruction
17
+ versions.map(&:destroy)
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # Returns a hash of versions grouped by the `item_id` attribute formatted like this: {:item_id => PaperTrail::Version}.
25
+ # If `item_id` or `date` is set, versions will be narrowed to those pointing at items with those ids that were created on specified date.
26
+ def gather_versions(item_id = nil, date = :all)
27
+ raise "`date` argument must receive a Timestamp or `:all`" unless date == :all || date.respond_to?(:to_date)
28
+ versions = item_id ? PaperTrail::Version.where(:item_id => item_id) : PaperTrail::Version
29
+ versions = versions.between(date.to_date, date.to_date + 1.day) unless date == :all
30
+ versions = PaperTrail::Version.all if versions == PaperTrail::Version # if versions has not been converted to an ActiveRecord::Relation yet, do so now
31
+ versions.group_by(&:item_id)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ require 'singleton'
2
+
3
+ module PaperTrail
4
+ class Config
5
+ include Singleton
6
+ attr_accessor :enabled, :timestamp_field, :serializer, :version_limit
7
+
8
+ def initialize
9
+ @enabled = true # Indicates whether PaperTrail is on or off.
10
+ @timestamp_field = :created_at
11
+ @serializer = PaperTrail::Serializers::Yaml
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ if defined? World
2
+ # before hook for Cucumber
3
+ before do
4
+ ::PaperTrail.enabled = false
5
+ ::PaperTrail.whodunnit = nil
6
+ ::PaperTrail.controller_info = {} if defined? ::Rails
7
+ end
8
+
9
+ module PaperTrail
10
+ module Cucumber
11
+ module Extensions
12
+ # :call-seq:
13
+ # with_versioning
14
+ #
15
+ # enable versioning for specific blocks
16
+
17
+ def with_versioning
18
+ was_enabled = ::PaperTrail.enabled?
19
+ ::PaperTrail.enabled = true
20
+ begin
21
+ yield
22
+ ensure
23
+ ::PaperTrail.enabled = was_enabled
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ World PaperTrail::Cucumber::Extensions
31
+ end
@@ -0,0 +1,79 @@
1
+ module PaperTrail
2
+ module Rails
3
+ module Controller
4
+
5
+ def self.included(base)
6
+ if defined?(ActionController) && base == ActionController::Base
7
+ base.before_filter :set_paper_trail_enabled_for_controller
8
+ base.before_filter :set_paper_trail_whodunnit, :set_paper_trail_controller_info
9
+ end
10
+ end
11
+
12
+ protected
13
+
14
+ # Returns the user who is responsible for any changes that occur.
15
+ # By default this calls `current_user` and returns the result.
16
+ #
17
+ # Override this method in your controller to call a different
18
+ # method, e.g. `current_person`, or anything you like.
19
+ def user_for_paper_trail
20
+ current_user if defined?(current_user)
21
+ end
22
+
23
+ # Returns any information about the controller or request that you
24
+ # want PaperTrail to store alongside any changes that occur. By
25
+ # default this returns an empty hash.
26
+ #
27
+ # Override this method in your controller to return a hash of any
28
+ # information you need. The hash's keys must correspond to columns
29
+ # in your `versions` table, so don't forget to add any new columns
30
+ # you need.
31
+ #
32
+ # For example:
33
+ #
34
+ # {:ip => request.remote_ip, :user_agent => request.user_agent}
35
+ #
36
+ # The columns `ip` and `user_agent` must exist in your `versions` # table.
37
+ #
38
+ # Use the `:meta` option to `PaperTrail::Model::ClassMethods.has_paper_trail`
39
+ # to store any extra model-level data you need.
40
+ def info_for_paper_trail
41
+ {}
42
+ end
43
+
44
+ # Returns `true` (default) or `false` depending on whether PaperTrail should
45
+ # be active for the current request.
46
+ #
47
+ # Override this method in your controller to specify when PaperTrail should
48
+ # be off.
49
+ def paper_trail_enabled_for_controller
50
+ true
51
+ end
52
+
53
+ private
54
+
55
+ # Tells PaperTrail whether versions should be saved in the current request.
56
+ def set_paper_trail_enabled_for_controller
57
+ ::PaperTrail.enabled_for_controller = paper_trail_enabled_for_controller
58
+ end
59
+
60
+ # Tells PaperTrail who is responsible for any changes that occur.
61
+ def set_paper_trail_whodunnit
62
+ ::PaperTrail.whodunnit = user_for_paper_trail if paper_trail_enabled_for_controller
63
+ end
64
+
65
+ # DEPRECATED: please use `set_paper_trail_whodunnit` instead.
66
+ def set_whodunnit
67
+ logger.warn '[PaperTrail]: the `set_whodunnit` controller method has been deprecated. Please rename to `set_paper_trail_whodunnit`.'
68
+ set_paper_trail_whodunnit
69
+ end
70
+
71
+ # Tells PaperTrail any information from the controller you want
72
+ # to store alongside any changes that occur.
73
+ def set_paper_trail_controller_info
74
+ ::PaperTrail.controller_info = info_for_paper_trail if paper_trail_enabled_for_controller
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,24 @@
1
+ if defined? RSpec
2
+ require 'rspec/core'
3
+ require 'rspec/matchers'
4
+ require File.expand_path('../rspec/extensions', __FILE__)
5
+
6
+ RSpec.configure do |config|
7
+ config.include ::PaperTrail::RSpec::Extensions
8
+
9
+ config.before(:each) do
10
+ ::PaperTrail.enabled = false
11
+ ::PaperTrail.whodunnit = nil
12
+ ::PaperTrail.controller_info = {} if defined?(::Rails) && defined?(::RSpec::Rails)
13
+ end
14
+
15
+ config.before(:each, :versioning => true) do
16
+ ::PaperTrail.enabled = true
17
+ end
18
+ end
19
+
20
+ RSpec::Matchers.define :be_versioned do
21
+ # check to see if the model has `has_paper_trail` declared on it
22
+ match { |actual| actual.kind_of?(::PaperTrail::Model::InstanceMethods) }
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module PaperTrail
2
+ module RSpec
3
+ module Extensions
4
+ # :call-seq:
5
+ # with_versioning
6
+ #
7
+ # enable versioning for specific blocks
8
+
9
+ def with_versioning
10
+ was_enabled = ::PaperTrail.enabled?
11
+ ::PaperTrail.enabled = true
12
+ begin
13
+ yield
14
+ ensure
15
+ ::PaperTrail.enabled = was_enabled
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Sinatra
2
+ module PaperTrail
3
+
4
+ # Register this module inside your Sinatra application to gain access to controller-level methods used by PaperTrail
5
+ def self.registered(app)
6
+ app.helpers Sinatra::PaperTrail
7
+ app.before { set_paper_trail_whodunnit }
8
+ end
9
+
10
+ protected
11
+
12
+ # Returns the user who is responsible for any changes that occur.
13
+ # By default this calls `current_user` and returns the result.
14
+ #
15
+ # Override this method in your controller to call a different
16
+ # method, e.g. `current_person`, or anything you like.
17
+ def user_for_paper_trail
18
+ current_user if defined?(current_user)
19
+ end
20
+
21
+ private
22
+
23
+ # Tells PaperTrail who is responsible for any changes that occur.
24
+ def set_paper_trail_whodunnit
25
+ ::PaperTrail.whodunnit = user_for_paper_trail if ::PaperTrail.enabled?
26
+ end
27
+
28
+ end
29
+
30
+ register Sinatra::PaperTrail if defined?(register)
31
+ end