Skip to content
This repository has been archived by the owner on Oct 12, 2019. It is now read-only.

"semantic_errors" helper #60

Merged
merged 2 commits into from Apr 4, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -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 %>

Expand Down
1 change: 1 addition & 0 deletions lib/formtastic-bootstrap/form_builder.rb
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions lib/formtastic-bootstrap/helpers/errors_helper.rb
@@ -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
112 changes: 112 additions & 0 deletions spec/helpers/semantic_errors_helper_spec.rb
@@ -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
4 changes: 4 additions & 0 deletions vendor/assets/stylesheets/formtastic-bootstrap.css
@@ -1,3 +1,7 @@
.hidden {
display: none;
}

.alert.alert-error .error-list {
margin: 0px;
}