Permalink
Browse files

Merge pull request #60 from nzaillian/master

"semantic_errors" helper
  • Loading branch information...
2 parents d30df7f + 057f708 commit b8a2a4e6736b24e6f12f63c572f0d4f4d8dfb0d2 @sodabrew sodabrew committed Apr 4, 2013
View
@@ -54,7 +54,7 @@ made to generate the HTML expected by Bootstrap while still generating the rich
<%= f.input :title, :hint => "This is the title!" %>
<% end %>
<%= f.actions do %>
- <%= f.submit %>
+ <%= f.action :submit %>
<% end %>
<% end %>
@@ -31,6 +31,7 @@ def self.default_hint_class=(hint_class)
include FormtasticBootstrap::Helpers::InputHelper # Revisit
include FormtasticBootstrap::Helpers::InputsHelper
+ include FormtasticBootstrap::Helpers::ErrorsHelper
include FormtasticBootstrap::Helpers::ActionHelper
include FormtasticBootstrap::Helpers::ActionsHelper
# include Formtastic::Helpers::ErrorsHelper
@@ -0,0 +1,70 @@
+module FormtasticBootstrap
+ module Helpers
+ module ErrorsHelper
+ include Formtastic::Helpers::FileColumnDetection
+ include Formtastic::Helpers::Reflection
+ include Formtastic::LocalizedString
+
+ INLINE_ERROR_TYPES = [:sentence, :list, :first]
+
+ # Generates a bootstrap error alert element containing
+ # an unordered list of error messages on the base object and optionally for a given
+ # set of named attribute. This is idea for rendering a block of error messages at the top of
+ # the form for hidden/special/virtual attributes (the Paperclip Rails plugin does this), or
+ # errors on the base model.
+ #
+ # A hash can be used as the last set of arguments to pass HTML attributes to the `<ul>`
+ # wrapper.
+ #
+ # @example A list of errors on the base model
+ # <%= semantic_form_for ... %>
+ # <%= f.semantic_errors %>
+ # ...
+ # <% end %>
+ #
+ # @example A list of errors on the base and named attributes
+ # <%= semantic_form_for ... %>
+ # <%= f.semantic_errors :something_special %>
+ # ...
+ # <% end %>
+ #
+ # @example A list of errors on the base model, with custom HTML attributes
+ # <%= semantic_form_for ... %>
+ # <%= f.semantic_errors :class => "awesome" %>
+ # ...
+ # <% end %>
+ #
+ # @example A list of errors on the base model and named attributes, with custom HTML attributes
+ # <%= semantic_form_for ... %>
+ # <%= f.semantic_errors :something_special, :something_else, :class => "awesome", :onclick => "Awesome();" %>
+ # ...
+ # <% end %>
+ def semantic_errors(*args)
+ html_options = args.extract_options!
+ args = args - [:base]
+ full_errors = args.inject([]) do |array, method|
+ attribute = localized_string(method, method.to_sym, :label) || humanized_attribute_name(method)
+ errors = Array(@object.errors[method.to_sym]).to_sentence
+ errors.present? ? array << [attribute, errors].join(" ") : array ||= []
+ end
+ full_errors << @object.errors[:base]
+ full_errors.flatten!
+ full_errors.compact!
+ return nil if full_errors.blank?
+
+ if html_options[:class].blank?
+ html_options[:class] = "alert alert-error"
+ else
+ html_options[:class] = "alert alert-error " + html_options[:class]
+ end
+
+ template.content_tag(:div, html_options) do
+ template.content_tag(:button, "&times;".html_safe, :class => "close", "data-dismiss" => "alert") +
+ template.content_tag(:ul, {class: "error-list"}) do
+ Formtastic::Util.html_safe(full_errors.map { |error| template.content_tag(:li, Formtastic::Util.html_safe(error)) }.join)
+ end
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,112 @@
+# encoding: utf-8
+require 'spec_helper'
+
+describe 'FormtasticBootstrap::FormBuilder#semantic_errors' do
+
+ include FormtasticSpecHelper
+
+ before do
+ @output_buffer = ''
+ mock_everything
+ @title_errors = ['must not be blank', 'must be awesome']
+ @base_errors = ['base error message', 'nasty error']
+ @base_error = 'one base error'
+ @errors = mock('errors')
+ @new_post.stub!(:errors).and_return(@errors)
+ end
+
+ describe 'when there is only one error on base' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error)
+ end
+
+ it 'should render an alert with an unordered list' do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_errors.should have_tag('.alert.alert-error ul.error-list li', @base_error)
+ end
+ end
+ end
+
+ describe 'when there is more than one error on base' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_errors)
+ end
+
+ it 'should render an unordered list' do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_errors.should have_tag('.alert.alert-error ul.error-list')
+ @base_errors.each do |error|
+ builder.semantic_errors.should have_tag('.alert.alert-error ul.error-list li', error)
+ end
+ end
+ end
+ end
+
+ describe 'when there are errors on title' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:title)).and_return(@title_errors)
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return([])
+ end
+
+ it 'should render an unordered list' do
+ semantic_form_for(@new_post) do |builder|
+ title_name = builder.send(:localized_string, :title, :title, :label) || builder.send(:humanized_attribute_name, :title)
+ builder.semantic_errors(:title).should have_tag('.alert.alert-error ul.error-list li', title_name << " " << @title_errors.to_sentence)
+ end
+ end
+ end
+
+ describe 'when there are errors on title and base' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:title)).and_return(@title_errors)
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error)
+ end
+
+ it 'should render an unordered list' do
+ semantic_form_for(@new_post) do |builder|
+ title_name = builder.send(:localized_string, :title, :title, :label) || builder.send(:humanized_attribute_name, :title)
+ builder.semantic_errors(:title).should have_tag('.alert.alert-error ul.error-list li', title_name << " " << @title_errors.to_sentence)
+ builder.semantic_errors(:title).should have_tag('.alert.alert-error ul.error-list li', @base_error)
+ end
+ end
+ end
+
+ describe 'when there are no errors' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:title)).and_return(nil)
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(nil)
+ end
+
+ it 'should return nil' do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_errors(:title).should be_nil
+ end
+ end
+ end
+
+ describe 'when there is one error on base and options with class is passed' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error)
+ end
+
+ it 'should render an unordered list with given class' do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_errors(:class => "awesome").should have_tag('.alert.alert-error.awesome ul.error-list li', @base_error)
+ end
+ end
+ end
+
+ describe 'when :base is passed in as an argument' do
+ before do
+ @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error)
+ end
+
+ it 'should ignore :base and only render base errors once' do
+ semantic_form_for(@new_post) do |builder|
+ builder.semantic_errors(:base).should have_tag('ul li', :count => 1)
+ builder.semantic_errors(:base).should_not have_tag('ul li', "Base #{@base_error}")
+ end
+ end
+ end
+
+end
@@ -1,3 +1,7 @@
.hidden {
display: none;
}
+
+.alert.alert-error .error-list {
+ margin: 0px;
+}

0 comments on commit b8a2a4e

Please sign in to comment.