From f8aeeca0a93d42f9831bb55af17a013327f37f5e Mon Sep 17 00:00:00 2001 From: Adam Meehan Date: Thu, 26 Jan 2012 22:44:01 +1100 Subject: [PATCH] A fix for ActiveRecord 3.1.x and plugin parser not working together (issue #52) --- Gemfile | 6 +-- lib/validates_timeliness/attribute_methods.rb | 6 ++- lib/validates_timeliness/orm/active_record.rb | 44 ++++++++++++++++--- .../attribute_methods_spec.rb | 2 +- .../orm/active_record_spec.rb | 16 ++++++- 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index b38badc..bce0b34 100644 --- a/Gemfile +++ b/Gemfile @@ -2,9 +2,9 @@ source 'http://rubygems.org' gemspec -gem 'rails', '3.1.0' -gem 'rspec', '~> 2.6' -gem 'rspec-rails', '~> 2.6' +gem 'rails', '3.1.3' +gem 'rspec', '~> 2.8' +gem 'rspec-rails', '~> 2.8' gem 'timecop' gem 'rspec_tag_matchers' gem 'ruby-debug', :platforms => [:ruby_18, :jruby] diff --git a/lib/validates_timeliness/attribute_methods.rb b/lib/validates_timeliness/attribute_methods.rb index 9e7d3e4..e8bf9c9 100644 --- a/lib/validates_timeliness/attribute_methods.rb +++ b/lib/validates_timeliness/attribute_methods.rb @@ -33,11 +33,13 @@ module ValidatesTimeliness def define_timeliness_write_method(attr_name) method_body, line = <<-EOV, __LINE__ + 1 def #{attr_name}=(value) + original_value = value @timeliness_cache ||= {} - @timeliness_cache["#{attr_name}"] = value + @timeliness_cache["#{attr_name}"] = original_value #{ "if value.is_a?(String)\n#{timeliness_type_cast_code(attr_name, 'value')}\nend" if ValidatesTimeliness.use_plugin_parser } - super + + super(value) end EOV generated_timeliness_methods.module_eval(method_body, __FILE__, line) diff --git a/lib/validates_timeliness/orm/active_record.rb b/lib/validates_timeliness/orm/active_record.rb index 3cfd660..72852b9 100644 --- a/lib/validates_timeliness/orm/active_record.rb +++ b/lib/validates_timeliness/orm/active_record.rb @@ -3,12 +3,40 @@ module ValidatesTimeliness module ActiveRecord extend ActiveSupport::Concern + def self.use_plugin_cache? + ::ActiveRecord::VERSION::STRING < '3.1.0' + end + + included do + unless ValidatesTimeliness::ORM::ActiveRecord.use_plugin_cache? + # Just use the built-in before_type_cast retrieval + alias_method :_timeliness_raw_value_for, :read_attribute_before_type_cast + end + end + module ClassMethods def define_attribute_methods super - # Define write method and before_type_cast method - use_before_type_cast = ::ActiveRecord::VERSION::STRING < '3.1.0' - define_timeliness_methods(use_before_type_cast) + use_before_type_cast = ValidatesTimeliness::ORM::ActiveRecord.use_plugin_cache? + + if use_before_type_cast || ValidatesTimeliness.use_plugin_parser + define_timeliness_methods(use_before_type_cast) + end + end + + # ActiveRecord >= 3.1.x has correct before_type_cast implementation to support plugin, except parser + unless ValidatesTimeliness::ORM::ActiveRecord.use_plugin_cache? + def define_timeliness_write_method(attr_name) + method_body, line = <<-EOV, __LINE__ + 1 + def #{attr_name}=(value) + original_value = value + if original_value.is_a?(String)\n#{timeliness_type_cast_code(attr_name, 'value')}\nend + super(value) + @attributes['#{attr_name}'] = original_value + end + EOV + generated_timeliness_methods.module_eval(method_body, __FILE__, line) + end end def timeliness_attribute_timezone_aware?(attr_name) @@ -30,10 +58,14 @@ module ValidatesTimeliness end end - def reload(*args) - _clear_timeliness_cache - super + # ActiveRecord >= 3.1.x needs no cached cleared + if use_plugin_cache? + def reload(*args) + _clear_timeliness_cache + super + end end + end end end diff --git a/spec/validates_timeliness/attribute_methods_spec.rb b/spec/validates_timeliness/attribute_methods_spec.rb index e6864a4..f600025 100644 --- a/spec/validates_timeliness/attribute_methods_spec.rb +++ b/spec/validates_timeliness/attribute_methods_spec.rb @@ -31,7 +31,7 @@ describe ValidatesTimeliness::AttributeMethods do it 'should cache attribute raw value' do r = PersonWithCache.new r.birth_datetime = date_string = '2010-01-01' - r._timeliness_raw_value_for(:birth_datetime).should == date_string + r._timeliness_raw_value_for('birth_datetime').should == date_string end it 'should not overwrite user defined methods' do diff --git a/spec/validates_timeliness/orm/active_record_spec.rb b/spec/validates_timeliness/orm/active_record_spec.rb index af022d4..37ec2a3 100644 --- a/spec/validates_timeliness/orm/active_record_spec.rb +++ b/spec/validates_timeliness/orm/active_record_spec.rb @@ -29,7 +29,7 @@ describe ValidatesTimeliness, 'ActiveRecord' do it 'should cache attribute raw value' do r = EmployeeWithCache.new r.birth_datetime = date_string = '2010-01-01' - r._timeliness_raw_value_for(:birth_datetime).should == date_string + r._timeliness_raw_value_for('birth_datetime').should == date_string end context "with plugin parser" do @@ -83,7 +83,7 @@ describe ValidatesTimeliness, 'ActiveRecord' do r.birth_date = '2010-01-01' r.reload - r._timeliness_raw_value_for(:birth_date).should be_nil + r._timeliness_raw_value_for('birth_date').should be_nil end end @@ -106,5 +106,17 @@ describe ValidatesTimeliness, 'ActiveRecord' do r = Employee.last r.birth_datetime_before_type_cast.should match(/2010-01-01 00:00:00/) end + + context "with plugin parser" do + with_config(:use_plugin_parser, true) + + it 'should return original value' do + r = Employee.new + r.birth_datetime = date_string = '2010-01-31' + + r.birth_datetime_before_type_cast.should == date_string + end + end + end end