Skip to content

Commit

Permalink
Automatically set maxlength if object is an ActiveModel and the field…
Browse files Browse the repository at this point in the history
…s method has a maximum length validation
  • Loading branch information
koppen authored and mjonuschat committed Sep 27, 2010
1 parent 099fb73 commit 98ceff5
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 12 deletions.
17 changes: 16 additions & 1 deletion lib/formtastic.rb
Expand Up @@ -1634,7 +1634,6 @@ def default_string_options(method, type) #:nodoc:
def get_maxlength_for(method)
# TODO: Extract this into a validations_for method in line with reflection_for, and update here and in method_required?
if @object && @object.class.respond_to?(:reflect_on_validations_for)

validation = @object.class.reflect_on_validations_for(method).find { |validation|
validation.macro == :validates_length_of &&
validation.name == method
Expand All @@ -1644,6 +1643,22 @@ def get_maxlength_for(method)
else
validation_max_limit = nil
end
else
# ActiveModel?
if @object && @object.class.respond_to?(:validators_on)
validation = @object.class.validators_on(method).find{ |validator|
validator.kind == :length &&
(validator.options.present? ? options_require_validation?(validator.options) : true)
}

if validation
validation_max_limit = validation.options[:maximum] || (validation.options[:within].present? ? validation.options[:within].max : nil)
else
validation_max_limit = nil
end
else
validation_max_limit = nil
end
end
return validation_max_limit
end
Expand Down
120 changes: 113 additions & 7 deletions spec/inputs/string_input_spec.rb
Expand Up @@ -32,14 +32,15 @@
it_should_apply_custom_for_to_label_when_input_html_id_provided(:string)
it_should_apply_error_logic_for_input_type(:string)

describe 'and the validation reflection plugin is available' do
def input_field_for_method_should_have_maxlength(method, maxlength)
form = semantic_form_for(@new_post) do |builder|
concat(builder.input(method))
end
output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form li input[@maxlength='#{maxlength}']")
def input_field_for_method_should_have_maxlength(method, maxlength)
form = semantic_form_for(@new_post) do |builder|
concat(builder.input(method))
end
output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form li input[@maxlength='#{maxlength}']")
end

describe 'and the validation reflection plugin is available' do

describe 'and validates_length_of was called for the method' do
it 'should have a maxlength matching validation range top' do
Expand All @@ -65,6 +66,111 @@ def input_field_for_method_should_have_maxlength(method, maxlength)
end
end
end

describe 'and its a ActiveModel' do
let(:default_maxlength) { 50 }

before do
@new_post.stub!(:class).and_return(::PostModel)
end

after do
@new_post.stub!(:class).and_return(::Post)
end

describe 'and validates_length_of was called for the method' do
it 'should have a maxlength' do
@new_post.class.should_receive(:validators_on).with(:title).at_least(2).and_return([
active_model_length_validator([:title], {:within => 5..42})
])

@new_post.class.should_receive(:validators_on).with(:body).at_least(2).and_return([
active_model_length_validator([:body], {:if => true, :maximum => 42})
])

input_field_for_method_should_have_maxlength(:title, 42)
input_field_for_method_should_have_maxlength(:body, 42)
end

it 'should have default maxlength if the optional :if condition is not satisifed' do
@new_post.class.should_receive(:validators_on).with(:title).at_least(2).and_return([
active_model_length_validator([:title], {:maximum => 42, :if => false})
])

input_field_for_method_should_have_maxlength(:title, default_maxlength)
end

# TODO make a matcher for this?
def should_be_required(options)
@new_post.class.should_receive(:validators_on).with(:body).and_return([
active_model_presence_validator([:body], options[:options])
])

form = semantic_form_for(@new_post) do |builder|
concat(builder.input(:body))
end

output_buffer.concat(form) if Formtastic::Util.rails3?

if options[:required]
output_buffer.should_not have_tag('form li.optional')
output_buffer.should have_tag('form li.required')
else
output_buffer.should have_tag('form li.optional')
output_buffer.should_not have_tag('form li.required')
end
end

def should_have_maxlength(maxlength, options)
@new_post.class.should_receive(:validators_on).with(:title).at_least(2).and_return([
active_model_length_validator([:title], options[:options])
])

form = semantic_form_for(@new_post) do |builder|
concat(builder.input(:title))
end

output_buffer.concat(form) if Formtastic::Util.rails3?
output_buffer.should have_tag("form li input[@maxlength='#{maxlength}']")
end

it 'should have default_maxlength if the optional :if proc evaluates to false' do
should_have_maxlength(default_maxlength, :options => {:maximum => 42, :if => proc { |record| false }})
end

it 'should have maxlength if the optional :if proc evaluates to true' do
should_have_maxlength(42, :options => { :maximum => 42, :if => proc { |record| true } })
end

it 'should have default maxlength if the optional :if with a method name evaluates to false' do
@new_post.should_receive(:specify_maxlength).and_return(false)
should_have_maxlength(default_maxlength, :options => { :maximum => 42, :if => :specify_maxlength })
end

it 'should have maxlength if the optional :if with a method name evaluates to true' do
@new_post.should_receive(:specify_maxlength).and_return(true)
should_have_maxlength(42, :options => { :maximum => 42, :if => :specify_maxlength })
end

it 'should have default maxlength if the optional :unless proc evaluates to true' do
should_have_maxlength(default_maxlength, :options => { :maximum => 42, :unless => proc { |record| true } })
end

it 'should have maxlength if the optional :unless proc evaluates to false' do
should_have_maxlength(42, :options => { :maximum => 42, :unless => proc { |record| false } })
end

it 'should have default maxlength if the optional :unless with a method name evaluates to true' do
@new_post.should_receive(:specify_maxlength).and_return(true)
should_have_maxlength(default_maxlength, :options => { :maximum => 42, :unless => :specify_maxlength })
end

it 'should have maxlength if the optional :unless with a method name evaluates to false' do
@new_post.should_receive(:specify_maxlength).and_return(false)
should_have_maxlength(42, :options => { :maximum => 42, :unless => :specify_maxlength })
end
end
end
end

describe "when no object is provided" do
Expand Down
16 changes: 12 additions & 4 deletions spec/spec_helper.rb
Expand Up @@ -53,12 +53,20 @@ def default_input_type(column_type, column_name = :generic_column_name)
return @default_type
end

def active_model_validator(kind, attributes, options = {})
validator = mock("ActiveModel::Validations::#{kind.to_s.titlecase}Validator", :attributes => attributes, :options => options)
validator.stub!(:kind).and_return(kind)
validator
end

def active_model_presence_validator(attributes, options = {})
presence_validator = mock('ActiveModel::Validations::PresenceValidator', :attributes => attributes, :options => options)
presence_validator.stub!(:kind).and_return(:presence)
presence_validator
active_model_validator(:presence, attributes, options)
end


def active_model_length_validator(attributes, options = {})
active_model_validator(:length, attributes, options)
end

class ::Post
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
Expand Down

0 comments on commit 98ceff5

Please sign in to comment.