Lookup errors in associations.

This commit is contained in:
Carlos Antonio da Silva 2009-12-11 01:18:56 -02:00
parent 94cb1efe00
commit 461f309bc7
6 changed files with 32 additions and 15 deletions

View File

@ -9,7 +9,7 @@ module SimpleForm
# of prepending the content available in the method content. # of prepending the content available in the method content.
class Base class Base
delegate :template, :object, :object_name, :attribute, :column, delegate :template, :object, :object_name, :attribute, :column,
:input_type, :options, :to => :@builder :reflection, :input_type, :options, :to => :@builder
def self.basename def self.basename
@basename ||= name.split("::").last.underscore.to_sym @basename ||= name.split("::").last.underscore.to_sym

View File

@ -9,11 +9,19 @@ module SimpleForm
end end
def errors def errors
@errors ||= object.errors[attribute] @errors ||= (errors_on_attribute + errors_on_association).compact
end
def errors_on_attribute
Array(object.errors[attribute])
end
def errors_on_association
reflection ? Array(object.errors[reflection.name]) : []
end end
def content def content
component_tag Array(errors).to_sentence component_tag errors.to_sentence
end end
end end
end end

View File

@ -1,14 +1,15 @@
module SimpleForm module SimpleForm
class FormBuilder < ActionView::Helpers::FormBuilder class FormBuilder < ActionView::Helpers::FormBuilder
attr_reader :template, :object_name, :object, :attribute, :column, :input_type, :options attr_reader :template, :object_name, :object, :attribute, :column,
:reflection, :input_type, :options
TERMINATOR = lambda { "" } TERMINATOR = lambda { "" }
# Basic input helper, combines all components in the stack to generate input # Basic input helper, combines all components in the stack to generate
# html based on options the user define and some guesses through # input html based on options the user define and some guesses through
# database column information. By default a call to input will generate # database column information. By default a call to input will generate
# label + input + hint (when defined) + errors (when exists), and all can be # label + input + hint (when defined) + errors (when exists), and all can
# configured inside a wrapper html. # be configured inside a wrapper html.
# #
# == Examples: # == Examples:
# #
@ -98,18 +99,18 @@ module SimpleForm
def association(attribute, options={}) def association(attribute, options={})
raise ArgumentError, "Association cannot be used in forms not associated with an object" unless @object raise ArgumentError, "Association cannot be used in forms not associated with an object" unless @object
association = find_association(attribute) @reflection = find_association_reflection(attribute)
raise "Association not found #{attribute.inspect}" unless association raise "Association not found #{attribute.inspect}" unless @reflection
attribute = association.options[:foreign_key] || :"#{association.name}_id" attribute = @reflection.options[:foreign_key] || :"#{@reflection.name}_id"
options[:collection] ||= begin options[:collection] ||= begin
find_options = { :conditions => options.delete(:conditions), find_options = { :conditions => options.delete(:conditions),
:order => options.delete(:order) } :order => options.delete(:order) }
association.klass.all(find_options) @reflection.klass.all(find_options)
end end
input(attribute, options) returning(input(attribute, options)) { @reflection = nil }
end end
# Creates a button: # Creates a button:
@ -248,7 +249,7 @@ module SimpleForm
end end
# Find association related to attribute # Find association related to attribute
def find_association(attribute) def find_association_reflection(attribute)
@object.class.reflect_on_association(attribute) if @object.class.respond_to?(:reflect_on_association) @object.class.reflect_on_association(attribute) if @object.class.respond_to?(:reflect_on_association)
end end

View File

@ -5,6 +5,7 @@ class ErrorTest < ActionView::TestCase
def with_error_for(object, attribute, type, options={}, &block) def with_error_for(object, attribute, type, options={}, &block)
simple_form_for object do |f| simple_form_for object do |f|
f.attribute = attribute f.attribute = attribute
f.reflection = Association.new(Company, :company, {}) if options.delete(:setup_association)
f.input_type = type f.input_type = type
f.options = options f.options = options
@ -46,4 +47,9 @@ class ErrorTest < ActionView::TestCase
with_error_for @user, :name, :string, :error_html => { :id => 'error', :class => 'yay' } with_error_for @user, :name, :string, :error_html => { :id => 'error', :class => 'yay' }
assert_select 'span#error.error.yay' assert_select 'span#error.error.yay'
end end
test 'error should find errors on attribute and association' do
with_error_for @user, :company_id, :select, :setup_association => true
assert_select 'span.error', 'must be valid and company must be present'
end
end end

View File

@ -64,6 +64,8 @@ class User < OpenStruct
:name => "can't be blank", :name => "can't be blank",
:description => "must be longer than 15 characters", :description => "must be longer than 15 characters",
:age => ["is not a number", "must be greater than 18"], :age => ["is not a number", "must be greater than 18"],
:company => "company must be present",
:company_id => "must be valid"
} }
end end
end end

View File

@ -16,7 +16,7 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
I18n.default_locale = :en I18n.default_locale = :en
class SimpleForm::FormBuilder class SimpleForm::FormBuilder
attr_accessor :attribute, :column, :input_type, :options attr_accessor :attribute, :column, :reflection, :input_type, :options
end end
class ActionView::TestCase class ActionView::TestCase