Merge branch 'master' into rails4
Conflicts: .travis.yml Gemfile
This commit is contained in:
commit
c2dbb1c154
|
@ -1,5 +1,8 @@
|
|||
## 2.7.1 (Unreleased)
|
||||
## 2.7.1
|
||||
|
||||
- [#206](https://github.com/airblade/paper_trail/issues/206) - Fixed Ruby 1.8.7 compatibility for tracking `object_changes`.
|
||||
- [#200](https://github.com/airblade/paper_trail/issues/200) - Fixed `next_version` method so that it returns the live model
|
||||
when called on latest reified version of a model prior to the live model.
|
||||
- [#197](https://github.com/airblade/paper_trail/issues/197) - PaperTrail now falls back on using YAML for serialization of
|
||||
serialized model attributes for storage in the `object` and `object_changes` columns in the `Version` table. This fixes
|
||||
compatibility for `Rails 3.0.x` for projects that employ the `serialize` declaration on a model.
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -1,5 +1,2 @@
|
|||
source :rubygems
|
||||
|
||||
gem 'rails', github: 'rails/rails'
|
||||
|
||||
source 'https://rubygems.org'
|
||||
gemspec
|
||||
|
|
|
@ -746,7 +746,7 @@ end
|
|||
By default, PaperTrail stores your changes as a YAML dump. You can override this with the serializer config option:
|
||||
|
||||
```ruby
|
||||
>> PaperTrail.config.serializer = MyCustomSerializer
|
||||
>> PaperTrail.serializer = MyCustomSerializer
|
||||
```
|
||||
|
||||
A valid serializer is a `module` (or `class`) that defines a `load` and `dump` method. These serializers are included in the gem for your convenience:
|
||||
|
|
|
@ -85,7 +85,7 @@ module PaperTrail
|
|||
def serialize_attributes_for_paper_trail(attributes)
|
||||
serialized_attributes.each do |key, coder|
|
||||
if attributes.key?(key)
|
||||
coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Rails 3.0.x's default serializers don't have a `dump` method
|
||||
coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method
|
||||
attributes[key] = coder.dump(attributes[key])
|
||||
end
|
||||
end
|
||||
|
@ -104,7 +104,7 @@ module PaperTrail
|
|||
def serialize_attribute_changes(changes)
|
||||
serialized_attributes.each do |key, coder|
|
||||
if changes.key?(key)
|
||||
coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Rails 3.0.x's default serializers don't have a `dump` method
|
||||
coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method
|
||||
old_value, new_value = changes[key]
|
||||
changes[key] = [coder.dump(old_value),
|
||||
coder.dump(new_value)]
|
||||
|
@ -155,15 +155,17 @@ module PaperTrail
|
|||
# Returns the object (not a Version) as it was most recently.
|
||||
def previous_version
|
||||
preceding_version = source_version ? source_version.previous : send(self.class.versions_association_name).last
|
||||
preceding_version.try :reify
|
||||
preceding_version.reify if preceding_version
|
||||
end
|
||||
|
||||
# Returns the object (not a Version) as it became next.
|
||||
# NOTE: if self (the item) was not reified from a version, i.e. it is the
|
||||
# "live" item, we return nil. Perhaps we should return self instead?
|
||||
def next_version
|
||||
# NOTE: if self (the item) was not reified from a version, i.e. it is the
|
||||
# "live" item, we return nil. Perhaps we should return self instead?
|
||||
subsequent_version = source_version ? source_version.next : nil
|
||||
subsequent_version.reify if subsequent_version
|
||||
subsequent_version = source_version.next
|
||||
subsequent_version ? subsequent_version.reify : self.class.find(self.id)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
# Executes the given method or block without creating a new version.
|
||||
|
@ -215,8 +217,8 @@ module PaperTrail
|
|||
end
|
||||
|
||||
def changes_for_paper_trail
|
||||
self.changes.keep_if do |key, value|
|
||||
notably_changed.include?(key)
|
||||
self.changes.delete_if do |key, value|
|
||||
!notably_changed.include?(key)
|
||||
end.tap do |changes|
|
||||
self.class.serialize_attribute_changes(changes) # Use serialized value for attributes when necessary
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module PaperTrail
|
||||
VERSION = '2.7.0'
|
||||
VERSION = '2.7.1'
|
||||
end
|
||||
|
|
|
@ -15,10 +15,11 @@ Gem::Specification.new do |s|
|
|||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
s.require_paths = ['lib']
|
||||
|
||||
s.add_dependency 'railties', '~> 4.0.0.beta'
|
||||
s.add_dependency 'activerecord', '~> 4.0.0.beta'
|
||||
s.add_dependency 'railties', '>= 4.0.0.beta', '< 5.0'
|
||||
s.add_dependency 'activerecord', '>= 4.0.0.beta', '< 5.0'
|
||||
|
||||
s.add_development_dependency 'rake'
|
||||
s.add_development_dependency 'sqlite3'
|
||||
s.add_development_dependency 'ffaker', '>= 1.15'
|
||||
s.add_development_dependency 'protected_attributes', '~> 1.0'
|
||||
end
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
class ProtectedWidget < Widget
|
||||
attr_accessible :name, :a_text
|
||||
end
|
|
@ -4,8 +4,9 @@ require "active_model/railtie"
|
|||
require "active_record/railtie"
|
||||
require "action_controller/railtie"
|
||||
require "action_view/railtie"
|
||||
require "protected_attributes" # Rails 4 requirement for using `attr_protected` and `attr_accessible`
|
||||
|
||||
Bundler.require
|
||||
Bundler.require(:default, Rails.env) if defined?(Bundler)
|
||||
require 'paper_trail'
|
||||
|
||||
module Dummy
|
||||
|
@ -32,13 +33,30 @@ module Dummy
|
|||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
# config.i18n.default_locale = :de
|
||||
|
||||
# JavaScript files you want as :defaults (application.js is always included).
|
||||
# config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
|
||||
|
||||
# Configure the default encoding used in templates for Ruby 1.9.
|
||||
config.encoding = "utf-8"
|
||||
|
||||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
config.filter_parameters += [:password]
|
||||
|
||||
# Enable escaping HTML in JSON.
|
||||
config.active_support.escape_html_entities_in_json = true
|
||||
|
||||
# Use SQL instead of Active Record's schema dumper when creating the database.
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
# like if you have constraints or database-specific column types
|
||||
# config.active_record.schema_format = :sql
|
||||
|
||||
# Enforce whitelist mode for mass assignment.
|
||||
# This will create an empty whitelist of attributes available for mass-assignment for all models
|
||||
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
|
||||
# parameters by using an attr_accessible or attr_protected declaration.
|
||||
config.active_record.whitelist_attributes = false
|
||||
|
||||
# Enable the asset pipeline
|
||||
config.assets.enabled = false
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
# config.assets.version = '1.0'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,25 +2,34 @@ Dummy::Application.configure do
|
|||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
# In the development environment your application's code is reloaded on
|
||||
# every request. This slows down response time but is perfect for development
|
||||
# since you don't have to restart the webserver when you make code changes.
|
||||
# every request. This slows down response time but is perfect for development
|
||||
# since you don't have to restart the web server when you make code changes.
|
||||
config.cache_classes = false
|
||||
|
||||
# Log error messages when you accidentally call methods on nil.
|
||||
config.whiny_nils = true
|
||||
|
||||
# Show full error reports and disable caching
|
||||
config.consider_all_requests_local = true
|
||||
config.action_view.debug_rjs = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Print deprecation notices to the Rails logger
|
||||
config.active_support.deprecation = :log
|
||||
|
||||
# Only use best-standards-support built into browsers
|
||||
config.action_dispatch.best_standards_support = :builtin
|
||||
|
||||
# Raise exception on mass assignment protection for Active Record models
|
||||
config.active_record.mass_assignment_sanitizer = :strict
|
||||
|
||||
# Log the query plan for queries taking more than this (works
|
||||
# with SQLite, MySQL, and PostgreSQL)
|
||||
config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
|
||||
# Do not compress assets
|
||||
config.assets.compress = false
|
||||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
Dummy::Application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
# The production environment is meant for finished, "live" apps.
|
||||
# Code is not reloaded between requests
|
||||
config.cache_classes = true
|
||||
|
||||
|
@ -9,31 +8,46 @@ Dummy::Application.configure do
|
|||
config.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Disable Rails's static asset server (Apache or nginx will already do this)
|
||||
config.serve_static_assets = false
|
||||
|
||||
# Compress JavaScripts and CSS
|
||||
config.assets.compress = true
|
||||
|
||||
# Don't fallback to assets pipeline if a precompiled asset is missed
|
||||
config.assets.compile = false
|
||||
|
||||
# Generate digests for assets URLs
|
||||
config.assets.digest = true
|
||||
|
||||
# Defaults to nil and saved in location specified by config.assets.prefix
|
||||
# config.assets.manifest = YOUR_PATH
|
||||
|
||||
# Specifies the header that your server uses for sending files
|
||||
config.action_dispatch.x_sendfile_header = "X-Sendfile"
|
||||
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
||||
|
||||
# For nginx:
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
|
||||
|
||||
# If you have no front-end server that supports something like X-Sendfile,
|
||||
# just comment this out and Rails will serve the files
|
||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||
# config.force_ssl = true
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Prepend all log lines with the following tags
|
||||
# config.log_tags = [ :subdomain, :uuid ]
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
|
||||
|
||||
# Use a different cache store in production
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
||||
# Disable Rails's static asset server
|
||||
# In production, Apache or nginx will already do this
|
||||
config.serve_static_assets = false
|
||||
|
||||
# Enable serving of images, stylesheets, and javascripts from an asset server
|
||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
|
||||
# config.assets.precompile += %w( search.js )
|
||||
|
||||
# Disable delivery errors, bad email addresses will be ignored
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
|
@ -46,4 +60,8 @@ Dummy::Application.configure do
|
|||
|
||||
# Send deprecation notices to registered listeners
|
||||
config.active_support.deprecation = :notify
|
||||
|
||||
# Log the query plan for queries taking more than this (works
|
||||
# with SQLite, MySQL, and PostgreSQL)
|
||||
# config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
end
|
||||
|
|
|
@ -2,13 +2,14 @@ Dummy::Application.configure do
|
|||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
# The test environment is used exclusively to run your application's
|
||||
# test suite. You never need to work with it otherwise. Remember that
|
||||
# test suite. You never need to work with it otherwise. Remember that
|
||||
# your test database is "scratch space" for the test suite and is wiped
|
||||
# and recreated between test runs. Don't rely on the data there!
|
||||
# and recreated between test runs. Don't rely on the data there!
|
||||
config.cache_classes = true
|
||||
|
||||
# Log error messages when you accidentally call methods on nil.
|
||||
config.whiny_nils = true
|
||||
# Configure static asset server for tests with Cache-Control for performance
|
||||
config.serve_static_assets = true
|
||||
config.static_cache_control = "public, max-age=3600"
|
||||
|
||||
# Show full error reports and disable caching
|
||||
config.consider_all_requests_local = true
|
||||
|
@ -18,17 +19,15 @@ Dummy::Application.configure do
|
|||
config.action_dispatch.show_exceptions = false
|
||||
|
||||
# Disable request forgery protection in test environment
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
# Tell Action Mailer not to deliver emails to the real world.
|
||||
# The :test delivery method accumulates sent emails in the
|
||||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test if config.respond_to?(:action_mailer)
|
||||
# config.action_mailer.delivery_method = :test
|
||||
|
||||
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
# like if you have constraints or database-specific column types
|
||||
# config.active_record.schema_format = :sql
|
||||
# Raise exception on mass assignment protection for Active Record models
|
||||
config.active_record.mass_assignment_sanitizer = :strict
|
||||
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
|
|
|
@ -628,6 +628,15 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|||
should 'return the current object for version_at after latest update' do
|
||||
assert_equal 'Digit', @widget.version_at(1.day.from_now).name
|
||||
end
|
||||
|
||||
context 'passing in a string representation of a timestamp' do
|
||||
should 'still return a widget when appropriate' do
|
||||
# need to add 1 second onto the timestamps before casting to a string, since casting a Time to a string drops the microseconds
|
||||
assert_equal 'Widget', @widget.version_at((@created + 1.second).to_s).name
|
||||
assert_equal 'Fidget', @widget.version_at((@first_update + 1.second).to_s).name
|
||||
assert_equal 'Digit', @widget.version_at((@second_update + 1.second).to_s).name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.versions_between' do
|
||||
|
@ -795,10 +804,10 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
should 'have a previous version' do
|
||||
assert_equal @widget.versions.last.reify, @widget.previous_version
|
||||
assert_equal @widget.versions.last.reify.name, @widget.previous_version.name
|
||||
end
|
||||
|
||||
should 'have a next version' do
|
||||
should 'not have a next version' do
|
||||
assert_nil @widget.next_version
|
||||
end
|
||||
end
|
||||
|
@ -806,21 +815,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|||
|
||||
describe 'A reified item' do
|
||||
setup do
|
||||
widget = Widget.create :name => 'Bob'
|
||||
%w( Tom Dick Jane ).each { |name| widget.update_attributes :name => name }
|
||||
@versions = widget.versions
|
||||
@second_widget = @versions[1].reify # first widget is null
|
||||
@last_widget = @versions.last.reify
|
||||
@widget = Widget.create :name => 'Bob'
|
||||
%w(Tom Dick Jane).each { |name| @widget.update_attributes :name => name }
|
||||
@second_widget = @widget.versions[1].reify # first widget is `nil`
|
||||
@last_widget = @widget.versions.last.reify
|
||||
end
|
||||
|
||||
should 'have a previous version' do
|
||||
assert_nil @second_widget.previous_version
|
||||
assert_equal @versions[-2].reify, @last_widget.previous_version
|
||||
assert_nil @second_widget.previous_version # `create` events return `nil` for `reify`
|
||||
assert_equal @widget.versions[-2].reify.name, @last_widget.previous_version.name
|
||||
end
|
||||
|
||||
should 'have a next version' do
|
||||
assert_equal @versions[2].reify, @second_widget.next_version
|
||||
assert_nil @last_widget.next_version
|
||||
assert_equal @widget.versions[2].reify.name, @second_widget.next_version.name
|
||||
assert_equal @last_widget.next_version.name, @widget.name
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1106,7 +1114,11 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|||
assert_equal 2, @doc.paper_trail_versions.length
|
||||
end
|
||||
|
||||
should 'respond to previous_version as normal' do
|
||||
should 'respond to `next_version` as normal' do
|
||||
assert_equal @doc.paper_trail_versions.last.reify.next_version.name, @doc.name
|
||||
end
|
||||
|
||||
should 'respond to `previous_version` as normal' do
|
||||
@doc.update_attributes :name => 'Doc 2'
|
||||
assert_equal 3, @doc.paper_trail_versions.length
|
||||
assert_equal 'Doc 1', @doc.previous_version.name
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ProtectedAttrsTest < ActiveSupport::TestCase
|
||||
|
||||
describe 'A model with `attr_accessible` created' do
|
||||
setup do
|
||||
@widget = ProtectedWidget.create! :name => 'Henry'
|
||||
@initial_attributes = @widget.attributes
|
||||
end
|
||||
|
||||
should { assert !ProtectedWidget.accessible_attributes.empty? }
|
||||
|
||||
should 'be `nil` in its previous version' do
|
||||
assert_nil @widget.previous_version
|
||||
end
|
||||
|
||||
describe 'which is then updated' do
|
||||
setup do
|
||||
@widget.assign_attributes(:name => 'Jeff', :a_text => 'Short statement')
|
||||
@widget.an_integer = 42
|
||||
@widget.save!
|
||||
end
|
||||
|
||||
should 'not be `nil` in its previous version' do
|
||||
assert_not_nil @widget.previous_version
|
||||
end
|
||||
|
||||
should 'the previous version should contain right attributes' do
|
||||
assert_equal @widget.previous_version.attributes, @initial_attributes
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -19,10 +19,13 @@ class SerializerTest < ActiveSupport::TestCase
|
|||
assert_nil @fluxor.versions[0].reify
|
||||
assert_equal 'Some text.', @fluxor.versions[1].reify.name
|
||||
|
||||
|
||||
# Check values are stored as YAML.
|
||||
assert_equal YAML.dump(@original_fluxor_attributes), @fluxor.versions[1].object
|
||||
assert_equal @original_fluxor_attributes, YAML.load(@fluxor.versions[1].object)
|
||||
# This test can't consistently pass in Ruby1.8 because hashes do no preserve order, which means the order of the
|
||||
# attributes in the YAML can't be ensured.
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
assert_equal YAML.dump(@original_fluxor_attributes), @fluxor.versions[1].object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -52,8 +55,12 @@ class SerializerTest < ActiveSupport::TestCase
|
|||
assert_equal 'Some text.', @fluxor.versions[1].reify.name
|
||||
|
||||
# Check values are stored as JSON.
|
||||
assert_equal ActiveSupport::JSON.encode(@original_fluxor_attributes), @fluxor.versions[1].object
|
||||
assert_equal @original_fluxor_attributes, ActiveSupport::JSON.decode(@fluxor.versions[1].object)
|
||||
# This test can't consistently pass in Ruby1.8 because hashes do no preserve order, which means the order of the
|
||||
# attributes in the JSON can't be ensured.
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
assert_equal ActiveSupport::JSON.encode(@original_fluxor_attributes), @fluxor.versions[1].object
|
||||
end
|
||||
end
|
||||
|
||||
should 'store object_changes' do
|
||||
|
|
Loading…
Reference in New Issue