mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-22 22:06:45 +00:00
Validation support for ActiveModel::Validations without a shim
move validation helpers into ActiveModel::Validations for default base support add check if attribute methods shim is being used refactor specs for helper and attribute methods separation more mongoid workarounds due to incorrect use of AS::Concern
This commit is contained in:
parent
5f31f40413
commit
6e67d45274
@ -1,5 +1,5 @@
|
||||
ValidatesTimeliness.setup do |config|
|
||||
# Add plugin to supported ORMs (:active_record, :mongoid)
|
||||
# Extend ORM/ODMs for full support (:active_record, :mongoid).
|
||||
# config.extend_orms = [ :active_record ]
|
||||
#
|
||||
# User the plugin date/time parser which is stricter and extendable
|
||||
|
||||
@ -2,8 +2,24 @@ module ValidatesTimeliness
|
||||
module AttributeMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_inheritable_accessor :timeliness_validated_attributes
|
||||
self.timeliness_validated_attributes = []
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
public
|
||||
# Override in ORM shim
|
||||
def timeliness_attribute_timezone_aware?(attr_name)
|
||||
false
|
||||
end
|
||||
|
||||
# Override in ORM shim
|
||||
def timeliness_attribute_type(attr_name)
|
||||
:datetime
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def define_timeliness_methods(before_type_cast=false)
|
||||
@ -37,21 +53,9 @@ module ValidatesTimeliness
|
||||
EOV
|
||||
class_eval(method_body, __FILE__, line)
|
||||
end
|
||||
|
||||
# Override in ORM shim
|
||||
def timeliness_attribute_timezone_aware?(attr_name)
|
||||
false
|
||||
end
|
||||
|
||||
# Override in ORM shim
|
||||
def timeliness_attribute_type(attr_name)
|
||||
:datetime
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def _timeliness_raw_value_for(attr_name)
|
||||
@timeliness_cache && @timeliness_cache[attr_name.to_s]
|
||||
end
|
||||
@ -59,7 +63,6 @@ module ValidatesTimeliness
|
||||
def _clear_timeliness_cache
|
||||
@timeliness_cache = {}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -3,10 +3,10 @@ module ValidatesTimeliness
|
||||
module DateTimeSelect
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Intercepts the date and time select helpers to reuse the values from the
|
||||
# Intercepts the date and time select helpers to reuse the values from
|
||||
# the params rather than the parsed value. This allows invalid date/time
|
||||
# values to be redisplayed instead of blanks to aid correction by the user.
|
||||
# Its a minor usability improvement which is rarely an issue for the user.
|
||||
# It's a minor usability improvement which is rarely an issue for the user.
|
||||
|
||||
included do
|
||||
alias_method_chain :datetime_selector, :timeliness
|
||||
|
||||
@ -1,15 +1,7 @@
|
||||
module ValidatesTimeliness
|
||||
module HelperMethods
|
||||
extend ActiveSupport::Concern
|
||||
module ActiveModel
|
||||
module Validations
|
||||
|
||||
included do
|
||||
include ValidationMethods
|
||||
extend ValidationMethods
|
||||
class_inheritable_accessor :timeliness_validated_attributes
|
||||
self.timeliness_validated_attributes = []
|
||||
end
|
||||
|
||||
module ValidationMethods
|
||||
module HelperMethods
|
||||
def validates_date(*attr_names)
|
||||
timeliness_validation_for attr_names, :date
|
||||
end
|
||||
@ -24,11 +16,13 @@ module ValidatesTimeliness
|
||||
|
||||
def timeliness_validation_for(attr_names, type)
|
||||
options = _merge_attributes(attr_names).merge(:type => type)
|
||||
self.timeliness_validated_attributes ||= []
|
||||
self.timeliness_validated_attributes += (attr_names - self.timeliness_validated_attributes)
|
||||
validates_with Validator, options
|
||||
if respond_to?(:timeliness_validated_attributes)
|
||||
self.timeliness_validated_attributes ||= []
|
||||
self.timeliness_validated_attributes += (attr_names - self.timeliness_validated_attributes)
|
||||
end
|
||||
validates_with ValidatesTimeliness::Validator, options
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@ -32,7 +32,6 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
class ActiveRecord::Base
|
||||
include ValidatesTimeliness::HelperMethods
|
||||
include ValidatesTimeliness::AttributeMethods
|
||||
include ValidatesTimeliness::ORM::ActiveRecord
|
||||
end
|
||||
|
||||
@ -43,9 +43,18 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
module Mongoid::Document
|
||||
include ValidatesTimeliness::HelperMethods
|
||||
include ValidatesTimeliness::AttributeMethods
|
||||
include ValidatesTimeliness::ORM::Mongoid
|
||||
# Due to how Mongoid misuses ActiveSupport::Concern,
|
||||
# the only way to override a core component method is
|
||||
# using an append_features hook.
|
||||
#
|
||||
module TimelinessConcern
|
||||
def append_features(base)
|
||||
super
|
||||
base.send :include, ValidatesTimeliness::AttributeMethods
|
||||
base.send :include, ValidatesTimeliness::ORM::Mongoid
|
||||
end
|
||||
end
|
||||
extend TimelinessConcern
|
||||
|
||||
def reload_with_timeliness
|
||||
_clear_timeliness_cache
|
||||
|
||||
@ -37,10 +37,10 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
def validate_each(record, attr_name, value)
|
||||
raw_value = record._timeliness_raw_value_for(attr_name) || value
|
||||
raw_value = attribute_raw_value(record, attr_name) || value
|
||||
return if (@allow_nil && raw_value.nil?) || (@allow_blank && raw_value.blank?)
|
||||
|
||||
@timezone_aware = record.class.timeliness_attribute_timezone_aware?(attr_name)
|
||||
@timezone_aware = timezone_aware?(record, attr_name)
|
||||
value = parse(raw_value) if value.is_a?(String) || options[:format]
|
||||
value = type_cast_value(value, @type)
|
||||
|
||||
@ -66,6 +66,17 @@ module ValidatesTimeliness
|
||||
value.strftime(format)
|
||||
end
|
||||
|
||||
def attribute_raw_value(record, attr_name)
|
||||
if record.respond_to?(:_timeliness_raw_value_for)
|
||||
record._timeliness_raw_value_for(attr_name)
|
||||
end
|
||||
end
|
||||
|
||||
def timezone_aware?(record, attr_name)
|
||||
record.class.respond_to?(:timeliness_attribute_timezone_aware?) &&
|
||||
record.class.timeliness_attribute_timezone_aware?(attr_name)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -24,15 +24,11 @@ LOCALE_PATH = File.expand_path(File.dirname(__FILE__) + '/../lib/generators/vali
|
||||
I18n.load_path.unshift(LOCALE_PATH)
|
||||
|
||||
# Extend TestModel as you would another ORM/ODM module
|
||||
module TestModel
|
||||
include ValidatesTimeliness::HelperMethods
|
||||
module TestModelShim
|
||||
extend ActiveSupport::Concern
|
||||
include ValidatesTimeliness::AttributeMethods
|
||||
|
||||
def self.included(base)
|
||||
base.extend HookMethods
|
||||
end
|
||||
|
||||
module HookMethods
|
||||
module ClassMethods
|
||||
# Hook method for attribute method generation
|
||||
def define_attribute_methods(attr_names)
|
||||
super
|
||||
@ -57,6 +53,10 @@ class Person
|
||||
define_attribute_methods model_attributes.keys
|
||||
end
|
||||
|
||||
class PersonWithShim < Person
|
||||
include TestModelShim
|
||||
end
|
||||
|
||||
ActiveRecord::Base.time_zone_aware_attributes = true
|
||||
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'})
|
||||
ActiveRecord::Migration.verbose = false
|
||||
@ -82,7 +82,7 @@ Rspec.configure do |c|
|
||||
c.include(RspecTagMatchers)
|
||||
c.before do
|
||||
Person.reset_callbacks(:validate)
|
||||
Person.timeliness_validated_attributes = []
|
||||
PersonWithShim.timeliness_validated_attributes = []
|
||||
Person._validators.clear
|
||||
Employee.reset_callbacks(:validate)
|
||||
Employee.timeliness_validated_attributes = []
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
module TestModel
|
||||
extend ActiveSupport::Concern
|
||||
extend ActiveSupport::Concern
|
||||
extend ActiveModel::Translation
|
||||
include ActiveModel::Validations
|
||||
include ActiveModel::AttributeMethods
|
||||
|
||||
included do
|
||||
extend ActiveModel::Translation
|
||||
include ActiveModel::Validations
|
||||
include ActiveModel::AttributeMethods
|
||||
include DynamicMethods
|
||||
|
||||
attribute_method_suffix ""
|
||||
attribute_method_suffix "="
|
||||
cattr_accessor :model_attributes
|
||||
@ -32,18 +30,6 @@ module TestModel
|
||||
end
|
||||
end
|
||||
|
||||
module DynamicMethods
|
||||
def method_missing(method_id, *args, &block)
|
||||
if !self.class.attribute_methods_generated?
|
||||
self.class.define_attribute_methods self.class.model_attributes.keys.map(&:to_s)
|
||||
method_name = method_id.to_s
|
||||
send(method_id, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(attributes = nil)
|
||||
@attributes = self.class.model_attributes.inject({}) do |hash, column|
|
||||
hash[column.to_s] = nil
|
||||
@ -62,5 +48,15 @@ module TestModel
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing(method_id, *args, &block)
|
||||
if !self.class.attribute_methods_generated?
|
||||
self.class.define_attribute_methods self.class.model_attributes.keys.map(&:to_s)
|
||||
method_name = method_id.to_s
|
||||
send(method_id, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -2,12 +2,24 @@ require 'spec_helper'
|
||||
|
||||
describe ValidatesTimeliness::AttributeMethods do
|
||||
it 'should define _timeliness_raw_value_for instance method' do
|
||||
Person.instance_methods.should include('_timeliness_raw_value_for')
|
||||
PersonWithShim.instance_methods.should include('_timeliness_raw_value_for')
|
||||
end
|
||||
|
||||
describe ".timeliness_validated_attributes" do
|
||||
it 'should return attributes validated with plugin validator' do
|
||||
PersonWithShim.timeliness_validated_attributes = []
|
||||
PersonWithShim.validates_date :birth_date
|
||||
PersonWithShim.validates_time :birth_time
|
||||
PersonWithShim.validates_datetime :birth_datetime
|
||||
|
||||
PersonWithShim.timeliness_validated_attributes.should == [ :birth_date, :birth_time, :birth_datetime ]
|
||||
end
|
||||
end
|
||||
|
||||
context "attribute write method" do
|
||||
class PersonWithCache
|
||||
include TestModel
|
||||
include TestModelShim
|
||||
attribute :birth_date, :date
|
||||
attribute :birth_time, :time
|
||||
attribute :birth_datetime, :datetime
|
||||
@ -25,6 +37,7 @@ describe ValidatesTimeliness::AttributeMethods do
|
||||
context "with plugin parser" do
|
||||
class PersonWithParser
|
||||
include TestModel
|
||||
include TestModelShim
|
||||
attribute :birth_date, :date
|
||||
attribute :birth_time, :time
|
||||
attribute :birth_datetime, :datetime
|
||||
@ -57,7 +70,7 @@ describe ValidatesTimeliness::AttributeMethods do
|
||||
|
||||
context "before_type_cast method" do
|
||||
it 'should not be defined if ORM does not support it' do
|
||||
Person.instance_methods(false).should_not include("birth_datetime_before_type_cast")
|
||||
PersonWithShim.instance_methods(false).should_not include("birth_datetime_before_type_cast")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ValidatesTimeliness::HelperMethods do
|
||||
describe ValidatesTimeliness, 'HelperMethods' do
|
||||
it 'should define class validation methods' do
|
||||
Person.should respond_to(:validates_date)
|
||||
Person.should respond_to(:validates_time)
|
||||
@ -18,16 +18,4 @@ describe ValidatesTimeliness::HelperMethods do
|
||||
r.validates_date :birth_date
|
||||
r.errors[:birth_date].should_not be_empty
|
||||
end
|
||||
|
||||
describe ".timeliness_validated_attributes" do
|
||||
it 'should return attributes validated with plugin validator' do
|
||||
Person.timeliness_validated_attributes = []
|
||||
Person.validates_date :birth_date
|
||||
Person.validates_time :birth_time
|
||||
Person.validates_datetime :birth_datetime
|
||||
|
||||
Person.timeliness_validated_attributes.should == [ :birth_date, :birth_time, :birth_datetime ]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -101,6 +101,7 @@ describe ValidatesTimeliness::Validator do
|
||||
describe ":format option" do
|
||||
class PersonWithFormatOption
|
||||
include TestModel
|
||||
include TestModelShim
|
||||
attribute :birth_date, :date
|
||||
attribute :birth_time, :time
|
||||
attribute :birth_datetime, :datetime
|
||||
|
||||
Loading…
Reference in New Issue
Block a user