simple-form-3.2.0/0000755000175000017500000000000012623141213014153 5ustar terceiroterceirosimple-form-3.2.0/MIT-LICENSE0000644000175000017500000000210312623141213015603 0ustar terceiroterceiroCopyright (c) 2009-2015 Plataformatec http://plataformatec.com.br/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. simple-form-3.2.0/metadata.yml0000644000175000017500000001551412623141213016464 0ustar terceiroterceiro--- !ruby/object:Gem::Specification name: simple_form version: !ruby/object:Gem::Version version: 3.2.0 platform: ruby authors: - José Valim - Carlos Antônio - Rafael França autorequire: bindir: bin cert_chain: [] date: 2015-09-22 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: activemodel requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' - !ruby/object:Gem::Dependency name: actionpack requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' description: Forms made easy! email: opensource@plataformatec.com.br executables: [] extensions: [] extra_rdoc_files: [] files: - CHANGELOG.md - MIT-LICENSE - README.md - lib/generators/simple_form/install_generator.rb - lib/generators/simple_form/templates/_form.html.erb - lib/generators/simple_form/templates/_form.html.haml - lib/generators/simple_form/templates/_form.html.slim - lib/generators/simple_form/templates/config/initializers/simple_form.rb - lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb - lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb - lib/generators/simple_form/templates/config/locales/simple_form.en.yml - lib/generators/simple_form/templates/README - lib/generators/simple_form/USAGE - lib/simple_form/action_view_extensions/builder.rb - lib/simple_form/action_view_extensions/form_helper.rb - lib/simple_form/components/errors.rb - lib/simple_form/components/hints.rb - lib/simple_form/components/html5.rb - lib/simple_form/components/label_input.rb - lib/simple_form/components/labels.rb - lib/simple_form/components/maxlength.rb - lib/simple_form/components/min_max.rb - lib/simple_form/components/pattern.rb - lib/simple_form/components/placeholders.rb - lib/simple_form/components/readonly.rb - lib/simple_form/components.rb - lib/simple_form/error_notification.rb - lib/simple_form/form_builder.rb - lib/simple_form/helpers/autofocus.rb - lib/simple_form/helpers/disabled.rb - lib/simple_form/helpers/readonly.rb - lib/simple_form/helpers/required.rb - lib/simple_form/helpers/validators.rb - lib/simple_form/helpers.rb - lib/simple_form/i18n_cache.rb - lib/simple_form/inputs/base.rb - lib/simple_form/inputs/block_input.rb - lib/simple_form/inputs/boolean_input.rb - lib/simple_form/inputs/collection_check_boxes_input.rb - lib/simple_form/inputs/collection_input.rb - lib/simple_form/inputs/collection_radio_buttons_input.rb - lib/simple_form/inputs/collection_select_input.rb - lib/simple_form/inputs/date_time_input.rb - lib/simple_form/inputs/file_input.rb - lib/simple_form/inputs/grouped_collection_select_input.rb - lib/simple_form/inputs/hidden_input.rb - lib/simple_form/inputs/numeric_input.rb - lib/simple_form/inputs/password_input.rb - lib/simple_form/inputs/priority_input.rb - lib/simple_form/inputs/range_input.rb - lib/simple_form/inputs/string_input.rb - lib/simple_form/inputs/text_input.rb - lib/simple_form/inputs.rb - lib/simple_form/map_type.rb - lib/simple_form/railtie.rb - lib/simple_form/tags.rb - lib/simple_form/version.rb - lib/simple_form/wrappers/builder.rb - lib/simple_form/wrappers/leaf.rb - lib/simple_form/wrappers/many.rb - lib/simple_form/wrappers/root.rb - lib/simple_form/wrappers/single.rb - lib/simple_form/wrappers.rb - lib/simple_form.rb - test/action_view_extensions/builder_test.rb - test/action_view_extensions/form_helper_test.rb - test/components/label_test.rb - test/form_builder/association_test.rb - test/form_builder/button_test.rb - test/form_builder/error_notification_test.rb - test/form_builder/error_test.rb - test/form_builder/general_test.rb - test/form_builder/hint_test.rb - test/form_builder/input_field_test.rb - test/form_builder/label_test.rb - test/form_builder/wrapper_test.rb - test/generators/simple_form_generator_test.rb - test/inputs/boolean_input_test.rb - test/inputs/collection_check_boxes_input_test.rb - test/inputs/collection_radio_buttons_input_test.rb - test/inputs/collection_select_input_test.rb - test/inputs/datetime_input_test.rb - test/inputs/disabled_test.rb - test/inputs/discovery_test.rb - test/inputs/file_input_test.rb - test/inputs/general_test.rb - test/inputs/grouped_collection_select_input_test.rb - test/inputs/hidden_input_test.rb - test/inputs/numeric_input_test.rb - test/inputs/priority_input_test.rb - test/inputs/readonly_test.rb - test/inputs/required_test.rb - test/inputs/string_input_test.rb - test/inputs/text_input_test.rb - test/simple_form_test.rb - test/support/discovery_inputs.rb - test/support/misc_helpers.rb - test/support/mock_controller.rb - test/support/models.rb - test/test_helper.rb homepage: https://github.com/plataformatec/simple_form licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: simple_form rubygems_version: 2.0.3 signing_key: specification_version: 4 summary: Forms made easy! test_files: - test/action_view_extensions/builder_test.rb - test/action_view_extensions/form_helper_test.rb - test/components/label_test.rb - test/form_builder/association_test.rb - test/form_builder/button_test.rb - test/form_builder/error_notification_test.rb - test/form_builder/error_test.rb - test/form_builder/general_test.rb - test/form_builder/hint_test.rb - test/form_builder/input_field_test.rb - test/form_builder/label_test.rb - test/form_builder/wrapper_test.rb - test/generators/simple_form_generator_test.rb - test/inputs/boolean_input_test.rb - test/inputs/collection_check_boxes_input_test.rb - test/inputs/collection_radio_buttons_input_test.rb - test/inputs/collection_select_input_test.rb - test/inputs/datetime_input_test.rb - test/inputs/disabled_test.rb - test/inputs/discovery_test.rb - test/inputs/file_input_test.rb - test/inputs/general_test.rb - test/inputs/grouped_collection_select_input_test.rb - test/inputs/hidden_input_test.rb - test/inputs/numeric_input_test.rb - test/inputs/priority_input_test.rb - test/inputs/readonly_test.rb - test/inputs/required_test.rb - test/inputs/string_input_test.rb - test/inputs/text_input_test.rb - test/simple_form_test.rb - test/support/discovery_inputs.rb - test/support/misc_helpers.rb - test/support/mock_controller.rb - test/support/models.rb - test/test_helper.rb simple-form-3.2.0/test/0000755000175000017500000000000012623141213015132 5ustar terceiroterceirosimple-form-3.2.0/test/test_helper.rb0000644000175000017500000000354512623141213020004 0ustar terceiroterceirorequire 'bundler/setup' require 'minitest/autorun' require 'active_model' require 'action_controller' require 'action_view' ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) require 'action_view/template' require 'action_view/test_case' module Rails def self.env ActiveSupport::StringInquirer.new("test") end end $:.unshift File.expand_path("../../lib", __FILE__) require 'simple_form' require "rails/generators/test_case" require 'generators/simple_form/install_generator' Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file| require file unless file.end_with?('discovery_inputs.rb') end I18n.default_locale = :en require 'country_select' if defined?(HTMLSelector::NO_STRIP) HTMLSelector::NO_STRIP << "label" else ActionDispatch::Assertions::NO_STRIP << "label" end if ActiveSupport::TestCase.respond_to?(:test_order=) ActiveSupport::TestCase.test_order = :random end class ActionView::TestCase include MiscHelpers include SimpleForm::ActionViewExtensions::FormHelper setup :set_controller setup :setup_users def set_controller @controller = MockController.new end def setup_users(extra_attributes = {}) @user = User.build(extra_attributes) @validating_user = ValidatingUser.build({ home_picture: 'Home picture', age: 19, amount: 15, attempts: 1, company: [1] }.merge!(extra_attributes)) @other_validating_user = OtherValidatingUser.build({ age: 19, company: 1 }.merge!(extra_attributes)) end def protect_against_forgery? false end def user_path(*args) '/users' end def company_user_path(*args) '/company/users' end alias :users_path :user_path alias :super_user_path :user_path alias :validating_user_path :user_path alias :validating_users_path :user_path alias :other_validating_user_path :user_path end simple-form-3.2.0/test/action_view_extensions/0000755000175000017500000000000012623141213021720 5ustar terceiroterceirosimple-form-3.2.0/test/action_view_extensions/form_helper_test.rb0000644000175000017500000001261012623141213025606 0ustar terceiroterceirorequire 'test_helper' class FormHelperTest < ActionView::TestCase test 'SimpleForm for yields an instance of FormBuilder' do simple_form_for :user do |f| assert f.instance_of?(SimpleForm::FormBuilder) end end test 'SimpleForm adds default class to form' do with_concat_form_for(:user) assert_select 'form.simple_form' end test 'SimpleForm allows overriding default form class' do swap SimpleForm, default_form_class: "my_custom_class" do with_concat_form_for :user, html: { class: "override_class" } assert_no_select 'form.my_custom_class' assert_select 'form.override_class' end end # Remove this test when SimpleForm.form_class is removed in 4.x test 'SimpleForm allows overriding default form class, but not form class' do ActiveSupport::Deprecation.silence do swap SimpleForm, form_class: "fixed_class", default_form_class: "my_custom_class" do with_concat_form_for :user, html: { class: "override_class" } assert_no_select 'form.my_custom_class' assert_select 'form.fixed_class.override_class' end end end test 'SimpleForm uses default browser validations by default' do with_concat_form_for(:user) assert_no_select 'form[novalidate]' end test 'SimpleForm does not use default browser validations if specified in the configuration options' do swap SimpleForm, browser_validations: false do with_concat_form_for(:user) assert_select 'form[novalidate="novalidate"]' end end test 'disabled browser validations overrides default configuration' do with_concat_form_for(:user, html: { novalidate: true }) assert_select 'form[novalidate="novalidate"]' end test 'enabled browser validations overrides disabled configuration' do swap SimpleForm, browser_validations: false do with_concat_form_for(:user, html: { novalidate: false }) assert_no_select 'form[novalidate]' end end test 'SimpleForm adds object name as css class to form when object is not present' do with_concat_form_for(:user, html: { novalidate: true }) assert_select 'form.simple_form.user' end test 'SimpleForm adds :as option as css class to form when object is not present' do with_concat_form_for(:user, as: 'superuser') assert_select 'form.simple_form.superuser' end test 'SimpleForm adds object class name with new prefix as css class to form if record is not persisted' do @user.new_record! with_concat_form_for(@user) assert_select 'form.simple_form.new_user' end test 'SimpleForm adds :as option with new prefix as css class to form if record is not persisted' do @user.new_record! with_concat_form_for(@user, as: 'superuser') assert_select 'form.simple_form.new_superuser' end test 'SimpleForm adds edit class prefix as css class to form if record is persisted' do with_concat_form_for(@user) assert_select 'form.simple_form.edit_user' end test 'SimpleForm adds :as options with edit prefix as css class to form if record is persisted' do with_concat_form_for(@user, as: 'superuser') assert_select 'form.simple_form.edit_superuser' end test 'SimpleForm adds last object name as css class to form when there is array of objects' do with_concat_form_for([Company.new, @user]) assert_select 'form.simple_form.edit_user' end test 'SimpleForm does not add object class to form if css_class is specified' do with_concat_form_for(:user, html: { class: nil }) assert_no_select 'form.user' end test 'SimpleForm adds custom class to form if css_class is specified' do with_concat_form_for(:user, html: { class: 'my_class' }) assert_select 'form.my_class' end test 'passes options to SimpleForm' do with_concat_form_for(:user, url: '/account', html: { id: 'my_form' }) assert_select 'form#my_form' assert_select 'form[action="/account"]' end test 'form_for yields an instance of FormBuilder' do with_concat_form_for(:user) do |f| assert f.instance_of?(SimpleForm::FormBuilder) end end test 'fields_for with a hash like model yields an instance of FormBuilder' do with_concat_fields_for(:author, HashBackedAuthor.new) do |f| assert f.instance_of?(SimpleForm::FormBuilder) f.input :name end assert_select "input[name='author[name]'][value='hash backed author']" end test 'custom error proc is not destructive' do swap_field_error_proc do result = nil simple_form_for :user do |f| result = simple_fields_for 'address' do 'hello' end end assert_equal 'hello', result end end test 'custom error proc survives an exception' do swap_field_error_proc do begin simple_form_for :user do |f| simple_fields_for 'address' do raise 'an exception' end end rescue StandardError end end end test 'SimpleForm for swaps default action view field_error_proc' do expected_error_proc = lambda {} swap SimpleForm, field_error_proc: expected_error_proc do simple_form_for :user do |f| assert_equal expected_error_proc, ::ActionView::Base.field_error_proc end end end private def swap_field_error_proc(expected_error_proc = lambda {}) swap ActionView::Base, field_error_proc: expected_error_proc do yield assert_equal expected_error_proc, ActionView::Base.field_error_proc end end end simple-form-3.2.0/test/action_view_extensions/builder_test.rb0000644000175000017500000006301412623141213024736 0ustar terceiroterceirorequire 'test_helper' class BuilderTest < ActionView::TestCase def with_custom_form_for(object, *args, &block) with_concat_custom_form_for(object) do |f| assert f.instance_of?(CustomFormBuilder) yield f end end def with_collection_radio_buttons(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block) with_concat_form_for(object) do |f| f.collection_radio_buttons attribute, collection, value_method, text_method, options, html_options, &block end end def with_collection_check_boxes(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block) with_concat_form_for(object) do |f| f.collection_check_boxes attribute, collection, value_method, text_method, options, html_options, &block end end # COLLECTION RADIO test "collection radio accepts a collection and generate inputs from value method" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=radio][value=true]#user_active_true' assert_select 'form input[type=radio][value=false]#user_active_false' end test "collection radio accepts a collection and generate inputs from label method" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s assert_select 'form label.collection_radio_buttons[for=user_active_true]', 'true' assert_select 'form label.collection_radio_buttons[for=user_active_false]', 'false' end test "collection radio handles camelized collection values for labels correctly" do with_collection_radio_buttons @user, :active, ['Yes', 'No'], :to_s, :to_s assert_select 'form label.collection_radio_buttons[for=user_active_yes]', 'Yes' assert_select 'form label.collection_radio_buttons[for=user_active_no]', 'No' end test "collection radio sanitizes collection values for labels correctly" do with_collection_radio_buttons @user, :name, ['$0.99', '$1.99'], :to_s, :to_s assert_select 'label.collection_radio_buttons[for=user_name_099]', '$0.99' assert_select 'label.collection_radio_buttons[for=user_name_199]', '$1.99' end test "collection radio checks the correct value to local variables" do user = User.build(active: false) with_collection_radio_buttons user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=radio][value=true]' assert_select 'form input[type=radio][value=false][checked=checked]' end test "collection radio accepts checked item" do with_collection_radio_buttons @user, :active, [[1, true], [0, false]], :last, :first, checked: true assert_select 'form input[type=radio][value=true][checked=checked]' assert_no_select 'form input[type=radio][value=false][checked=checked]' end test "collection radio accepts checked item which has a value of false" do with_collection_radio_buttons @user, :active, [[1, true], [0, false]], :last, :first, checked: false assert_no_select 'form input[type=radio][value=true][checked=checked]' assert_select 'form input[type=radio][value=false][checked=checked]' end test "collection radio accepts multiple disabled items" do collection = [[1, true], [0, false], [2, 'other']] with_collection_radio_buttons @user, :active, collection, :last, :first, disabled: [true, false] assert_select 'form input[type=radio][value=true][disabled=disabled]' assert_select 'form input[type=radio][value=false][disabled=disabled]' assert_no_select 'form input[type=radio][value=other][disabled=disabled]' end test "collection radio accepts single disable item" do collection = [[1, true], [0, false]] with_collection_radio_buttons @user, :active, collection, :last, :first, disabled: true assert_select 'form input[type=radio][value=true][disabled=disabled]' assert_no_select 'form input[type=radio][value=false][disabled=disabled]' end test "collection radio accepts html options as input" do collection = [[1, true], [0, false]] with_collection_radio_buttons @user, :active, collection, :last, :first, {}, class: 'special-radio' assert_select 'form input[type=radio][value=true].special-radio#user_active_true' assert_select 'form input[type=radio][value=false].special-radio#user_active_false' end test "collection radio wraps the collection in the given collection wrapper tag" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul assert_select 'form ul input[type=radio]', count: 2 end test "collection radio does not render any wrapper tag by default" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' end test "collection radio does not wrap the collection when given falsy values" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: false assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' end test "collection radio uses the given class for collection wrapper tag" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul, collection_wrapper_class: "items-list" assert_select 'form ul.items-list input[type=radio]', count: 2 end test "collection radio uses no class for collection wrapper tag when no wrapper tag is given" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_class: "items-list" assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' assert_no_select '.items-list' end test "collection radio uses no class for collection wrapper tag by default" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul assert_select 'form ul' assert_no_select 'form ul[class]' end test "collection radio wrap items in a span tag by default" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s assert_select 'form span input[type=radio][value=true]#user_active_true + label' assert_select 'form span input[type=radio][value=false]#user_active_false + label' end test "collection radio wraps each item in the given item wrapper tag" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li assert_select 'form li input[type=radio]', count: 2 end test "collection radio does not wrap each item when given explicitly falsy value" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: false assert_select 'form input[type=radio]' assert_no_select 'form span input[type=radio]' end test "collection radio uses the given class for item wrapper tag" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li, item_wrapper_class: "inline" assert_select "form li.inline input[type=radio]", count: 2 end test "collection radio uses no class for item wrapper tag when no wrapper tag is given" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: nil, item_wrapper_class: "inline" assert_select 'form input[type=radio]', count: 2 assert_no_select 'form li' assert_no_select '.inline' end test "collection radio uses no class for item wrapper tag by default" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li assert_select "form li", count: 2 assert_no_select "form li[class]" end test "collection radio does not wrap input inside the label" do with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=radio] + label' assert_no_select 'form label input' end test "collection radio accepts a block to render the label as radio button wrapper" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label { b.radio_button } end assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]' assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]' end test "collection radio accepts a block to change the order of label and radio button" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label + b.radio_button end assert_select 'label[for=user_active_true] + input#user_active_true[type=radio]' assert_select 'label[for=user_active_false] + input#user_active_false[type=radio]' end test "collection radio with block helpers accept extra html options" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label(class: "radio_button") + b.radio_button(class: "radio_button") end assert_select 'label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]' assert_select 'label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]' end test "collection radio with block helpers allows access to current text and value" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label(:"data-value" => b.value) { b.radio_button + b.text } end assert_select 'label[for=user_active_true][data-value=true]', 'true' do assert_select 'input#user_active_true[type=radio]' end assert_select 'label[for=user_active_false][data-value=false]', 'false' do assert_select 'input#user_active_false[type=radio]' end end test "collection radio with block helpers allows access to the current object item in the collection to access extra properties" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label(class: b.object) { b.radio_button + b.text } end assert_select 'label.true[for=user_active_true]', 'true' do assert_select 'input#user_active_true[type=radio]' end assert_select 'label.false[for=user_active_false]', 'false' do assert_select 'input#user_active_false[type=radio]' end end test "collection radio with block helpers does not leak the template" do with_concat_form_for(@user) do |f| collection_input = f.collection_radio_buttons :active, [true, false], :to_s, :to_s do |b| b.label(class: b.object) { b.radio_button + b.text } end concat collection_input concat f.hidden_field :name end assert_select 'label.true[for=user_active_true]', text: 'true', count: 1 do assert_select 'input#user_active_true[type=radio]' end assert_select 'label.false[for=user_active_false]', text: 'false', count: 1 do assert_select 'input#user_active_false[type=radio]' end end # COLLECTION CHECK BOX test "collection check box accepts a collection and generate a serie of checkboxes for value method" do collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')] with_collection_check_boxes @user, :tag_ids, collection, :id, :name assert_select 'form input#user_tag_ids_1[type=checkbox][value="1"]' assert_select 'form input#user_tag_ids_2[type=checkbox][value="2"]' end test "collection check box generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection" do collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')] with_collection_check_boxes @user, :tag_ids, collection, :id, :name assert_select "form input[type=hidden][name='user[tag_ids][]'][value='']", count: 1 end test "collection check box accepts a collection and generate a serie of checkboxes with labels for label method" do collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')] with_collection_check_boxes @user, :tag_ids, collection, :id, :name assert_select 'form label.collection_check_boxes[for=user_tag_ids_1]', 'Tag 1' assert_select 'form label.collection_check_boxes[for=user_tag_ids_2]', 'Tag 2' end test "collection check box handles camelized collection values for labels correctly" do with_collection_check_boxes @user, :active, ['Yes', 'No'], :to_s, :to_s assert_select 'form label.collection_check_boxes[for=user_active_yes]', 'Yes' assert_select 'form label.collection_check_boxes[for=user_active_no]', 'No' end test "collection check box sanitizes collection values for labels correctly" do with_collection_check_boxes @user, :name, ['$0.99', '$1.99'], :to_s, :to_s assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99' assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99' end test "collection check box checks the correct value to local variables" do user = User.build(tag_ids: [1, 3]) collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes user, :tag_ids, collection, :first, :last assert_select 'form input[type=checkbox][value="1"][checked=checked]' assert_select 'form input[type=checkbox][value="3"][checked=checked]' assert_no_select 'form input[type=checkbox][value="2"][checked=checked]' end test "collection check box accepts selected values as :checked option" do collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3] assert_select 'form input[type=checkbox][value="1"][checked=checked]' assert_select 'form input[type=checkbox][value="3"][checked=checked]' assert_no_select 'form input[type=checkbox][value="2"][checked=checked]' end test "collection check boxes accepts selected string values as :checked option" do collection = (1..3).map { |i| [i, "Category #{i}"] } with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: ['1', '3'] assert_select 'input[type=checkbox][value="1"][checked=checked]' assert_select 'input[type=checkbox][value="3"][checked=checked]' assert_no_select 'input[type=checkbox][value="2"][checked=checked]' end test "collection check box accepts a single checked value" do collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: 3 assert_select 'form input[type=checkbox][value="3"][checked=checked]' assert_no_select 'form input[type=checkbox][value="1"][checked=checked]' assert_no_select 'form input[type=checkbox][value="2"][checked=checked]' end test "collection check box accepts selected values as :checked option and override the model values" do collection = (1..3).map { |i| [i, "Tag #{i}"] } @user.tag_ids = [2] with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3] assert_select 'form input[type=checkbox][value="1"][checked=checked]' assert_select 'form input[type=checkbox][value="3"][checked=checked]' assert_no_select 'form input[type=checkbox][value="2"][checked=checked]' end test "collection check box accepts multiple disabled items" do collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: [1, 3] assert_select 'form input[type=checkbox][value="1"][disabled=disabled]' assert_select 'form input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]' end test "collection check box accepts single disable item" do collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: 1 assert_select 'form input[type=checkbox][value="1"][disabled=disabled]' assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]' end test "collection check box accepts a proc to disabled items" do collection = (1..3).map { |i| [i, "Tag #{i}"] } with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: proc { |i| i.first == 1 } assert_select 'form input[type=checkbox][value="1"][disabled=disabled]' assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]' end test "collection check box accepts html options" do collection = [[1, 'Tag 1'], [2, 'Tag 2']] with_collection_check_boxes @user, :tag_ids, collection, :first, :last, {}, class: 'check' assert_select 'form input.check[type=checkbox][value="1"]' assert_select 'form input.check[type=checkbox][value="2"]' end test "collection check box with fields for" do collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')] with_concat_form_for(@user) do |f| f.fields_for(:post) do |p| p.collection_check_boxes :tag_ids, collection, :id, :name end end assert_select 'form input#user_post_tag_ids_1[type=checkbox][value="1"]' assert_select 'form input#user_post_tag_ids_2[type=checkbox][value="2"]' assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_1]', 'Tag 1' assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_2]', 'Tag 2' end test "collection check boxes wraps the collection in the given collection wrapper tag" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul assert_select 'form ul input[type=checkbox]', count: 2 end test "collection check boxes does not render any wrapper tag by default" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' end test "collection check boxes does not wrap the collection when given falsy values" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: false assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' end test "collection check boxes uses the given class for collection wrapper tag" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul, collection_wrapper_class: "items-list" assert_select 'form ul.items-list input[type=checkbox]', count: 2 end test "collection check boxes uses no class for collection wrapper tag when no wrapper tag is given" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_class: "items-list" assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' assert_no_select '.items-list' end test "collection check boxes uses no class for collection wrapper tag by default" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul assert_select 'form ul' assert_no_select 'form ul[class]' end test "collection check boxes wrap items in a span tag by default" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s assert_select 'form span input[type=checkbox]', count: 2 end test "collection check boxes wraps each item in the given item wrapper tag" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li assert_select 'form li input[type=checkbox]', count: 2 end test "collection check boxes does not wrap each item when given explicitly falsy value" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: false assert_select 'form input[type=checkbox]' assert_no_select 'form span input[type=checkbox]' end test "collection check boxes uses the given class for item wrapper tag" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li, item_wrapper_class: "inline" assert_select "form li.inline input[type=checkbox]", count: 2 end test "collection check boxes uses no class for item wrapper tag when no wrapper tag is given" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: nil, item_wrapper_class: "inline" assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form li' assert_no_select '.inline' end test "collection check boxes uses no class for item wrapper tag by default" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li assert_select "form li", count: 2 assert_no_select "form li[class]" end test "collection check box does not wrap input inside the label" do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s assert_select 'form input[type=checkbox] + label' assert_no_select 'form label input' end test "collection check boxes accepts a block to render the label as check box wrapper" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label { b.check_box } end assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]' assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]' end test "collection check boxes accepts a block to change the order of label and check box" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label + b.check_box end assert_select 'label[for=user_active_true] + input#user_active_true[type=checkbox]' assert_select 'label[for=user_active_false] + input#user_active_false[type=checkbox]' end test "collection check boxes with block helpers accept extra html options" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label(class: "check_box") + b.check_box(class: "check_box") end assert_select 'label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]' assert_select 'label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]' end test "collection check boxes with block helpers allows access to current text and value" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label(:"data-value" => b.value) { b.check_box + b.text } end assert_select 'label[for=user_active_true][data-value=true]', 'true' do assert_select 'input#user_active_true[type=checkbox]' end assert_select 'label[for=user_active_false][data-value=false]', 'false' do assert_select 'input#user_active_false[type=checkbox]' end end test "collection check boxes with block helpers allows access to the current object item in the collection to access extra properties" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label(class: b.object) { b.check_box + b.text } end assert_select 'label.true[for=user_active_true]', 'true' do assert_select 'input#user_active_true[type=checkbox]' end assert_select 'label.false[for=user_active_false]', 'false' do assert_select 'input#user_active_false[type=checkbox]' end end test "collection check boxes with block helpers does not leak the template" do with_concat_form_for(@user) do |f| collection_input = f.collection_check_boxes :active, [true, false], :to_s, :to_s do |b| b.label(class: b.object) { b.check_box + b.text } end concat collection_input concat f.hidden_field :name end assert_select 'label.true[for=user_active_true]', text: 'true', count: 1 do assert_select 'input#user_active_true[type=checkbox]' end assert_select 'label.false[for=user_active_false]', text: 'false', count: 1 do assert_select 'input#user_active_false[type=checkbox]' end end # SIMPLE FIELDS test "simple fields for is available and yields an instance of FormBuilder" do with_concat_form_for(@user) do |f| f.simple_fields_for(:posts) do |posts_form| assert posts_form.instance_of?(SimpleForm::FormBuilder) end end end test "fields for with a hash like model yeilds an instance of FormBuilder" do with_concat_form_for(:user) do |f| f.simple_fields_for(:author, HashBackedAuthor.new) do |author| assert author.instance_of?(SimpleForm::FormBuilder) author.input :name end end assert_select "input[name='user[author][name]'][value='hash backed author']" end test "fields for yields an instance of CustomBuilder if main builder is a CustomBuilder" do with_custom_form_for(:user) do |f| f.simple_fields_for(:company) do |company| assert company.instance_of?(CustomFormBuilder) end end end test "fields for yields an instance of FormBuilder if it was set in options" do with_custom_form_for(:user) do |f| f.simple_fields_for(:company, builder: SimpleForm::FormBuilder) do |company| assert company.instance_of?(SimpleForm::FormBuilder) end end end test "fields inherits wrapper option from the parent form" do swap_wrapper :another do simple_form_for(:user, wrapper: :another) do |f| f.simple_fields_for(:company) do |company| assert_equal :another, company.options[:wrapper] end end end end test "fields overrides wrapper option from the parent form" do swap_wrapper :another do simple_form_for(:user, wrapper: :another) do |f| f.simple_fields_for(:company, wrapper: false) do |company| assert_equal false, company.options[:wrapper] end end end end end simple-form-3.2.0/test/inputs/0000755000175000017500000000000012623141213016454 5ustar terceiroterceirosimple-form-3.2.0/test/inputs/boolean_input_test.rb0000644000175000017500000002025512623141213022702 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class BooleanInputTest < ActionView::TestCase test 'input generates a checkbox by default for boolean attributes' do with_input_for @user, :active, :boolean assert_select 'input[type=checkbox].boolean#user_active' assert_select 'label.boolean.optional', 'Active' end test 'input does not generate the label with the checkbox when label option is false' do with_input_for @user, :active, :boolean, label: false assert_select 'input[type=checkbox].boolean#user_active' assert_no_select 'label' end test 'input uses custom checked value' do @user.action = 'on' with_input_for @user, :action, :boolean, checked_value: 'on', unchecked_value: 'off' assert_select 'input[type=checkbox][value=on][checked=checked]' end test 'input uses custom unchecked value' do @user.action = 'off' with_input_for @user, :action, :boolean, checked_value: 'on', unchecked_value: 'off' assert_select 'input[type=checkbox][value=on]' assert_no_select 'input[checked=checked][value=on]' end test 'input generates hidden input with custom unchecked value' do with_input_for @user, :action, :boolean, checked_value: 'on', unchecked_value: 'off' assert_select 'input[type=hidden][value=off]' end test 'input uses inline boolean style by default' do with_input_for @user, :active, :boolean assert_select 'input.boolean + label.boolean.optional' assert_no_select 'label > input' end test 'input allows changing default boolean style config to nested, generating a default label and a manual hidden field for checkbox' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean assert_select 'label[for=user_active]', 'Active' assert_select 'label.boolean > input.boolean' assert_no_select 'input[type=checkbox] + label' end end test 'input boolean with nested allows :inline_label' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: 'I am so inline.' assert_select 'label.checkbox', text: ' I am so inline.' end end test 'input boolean with nested escapes :inline_label with HTML' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: 'I am so inline.' assert_no_select 'label.checkbox b' end end test 'input boolean with nested allows :inline_label with HTML when safe' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: 'I am so inline.'.html_safe assert_select 'label.checkbox b', text: 'I am so inline.' end end test 'input boolean with nested style creates an inline label using the default label text when inline_label option set to true' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: true assert_select 'label.checkbox', text: ' Active' end end test 'input boolean with nested style creates an inline label using the label text when inline_label option set to true' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: true, label_text: proc { 'New Active' } assert_select 'label.checkbox', text: ' New Active' end end test 'input boolean with nested style creates an inline label using the label html when inline_label option set to true' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, inline_label: true, label_text: proc { 'New Active' } assert_select 'label.checkbox', text: ' New Active' end end test 'input boolean with nested generates a manual hidden field for checkbox outside the label, to recreate Rails functionality with valid html5' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean assert_select "input[type=hidden][name='user[active]'] + label.boolean > input.boolean" assert_no_select 'input[type=checkbox] + label' end end test 'input boolean with nested generates a disabled hidden field for checkbox outside the label, if the field is disabled' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, disabled: true assert_select "input[type=hidden][name='user[active]'][disabled] + label.boolean > input.boolean[disabled]" end end test 'input accepts changing boolean style to nested through given options' do with_input_for @user, :active, :boolean, boolean_style: :nested assert_select 'label[for=user_active]', 'Active' assert_select 'label.boolean > input.boolean' assert_no_select 'input[type=checkbox] + label' end test 'input accepts changing boolean style to inline through given options, when default is nested' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, boolean_style: :inline assert_select 'label[for=user_active]', 'Active' assert_select 'input.boolean + label.boolean' assert_no_select 'label > input' end end test 'input with nested style allows disabling label' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, label: false assert_select 'input.boolean' assert_no_select 'label.boolean' end end test 'input with nested style allows customizing input_html' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean, input_html: { name: 'active_user' } assert_select "input[type=hidden][name=active_user] + label.boolean > input.boolean[name=active_user]" end end test 'input boolean works using :input only in wrapper config (no label_input)' do swap_wrapper do with_input_for @user, :active, :boolean assert_select 'label.boolean + input[type=hidden] + input.boolean' assert_no_select 'label.checkbox' end end test 'input boolean with nested style works using :input only in wrapper config (no label_input), adding the extra "checkbox" label wrapper' do swap_wrapper do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean assert_select 'label.boolean + input[type=hidden] + label.checkbox > input.boolean' end end end test 'input boolean with nested style works using :input only in wrapper config (no label_input), adding the extra label wrapper with custom class' do swap_wrapper do swap SimpleForm, boolean_style: :nested, boolean_label_class: 'foo' do with_input_for @user, :active, :boolean assert_select 'label.boolean + input[type=hidden] + label.foo > input.boolean' end end end test 'input boolean with nested style works using :label_input in wrapper config, adding "checkbox" class to label' do swap_wrapper :default, self.custom_wrapper_without_top_level do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :boolean assert_select 'input[type=hidden] + label.boolean.checkbox > input.boolean' end end end test 'input boolean with nested style works using :label_input in wrapper config, adding custom class to label' do swap_wrapper :default, self.custom_wrapper_without_top_level do swap SimpleForm, boolean_style: :nested, boolean_label_class: 'foo' do with_input_for @user, :active, :boolean assert_select 'input[type=hidden] + label.boolean.foo > input.boolean' end end end test 'input boolean without additional classes adds "checkbox" class to label' do swap_wrapper :default, self.custom_wrapper_without_top_level do swap SimpleForm, boolean_style: :nested, generate_additional_classes_for: [:input] do with_input_for @user, :active, :boolean assert_select 'label' assert_select 'label.checkbox' assert_no_select 'label.boolean' end end end test 'input boolean works with wrapper config defining a class for the input' do swap_wrapper :default, self.custom_wrapper_with_input_class do with_input_for @user, :active, :boolean assert_select 'input.boolean.inline-class' end end end simple-form-3.2.0/test/inputs/required_test.rb0000644000175000017500000001156212623141213021665 0ustar terceiroterceirorequire 'test_helper' class RequiredTest < ActionView::TestCase # REQUIRED AND PRESENCE VALIDATION test 'builder input obtains required from ActiveModel::Validations when it is included' do with_form_for @validating_user, :name assert_select 'input.required[required]#validating_user_name' with_form_for @validating_user, :status assert_select 'input.optional#validating_user_status' end test 'builder input allows overriding required when ActiveModel::Validations is included' do with_form_for @validating_user, :name, required: false assert_select 'input.optional#validating_user_name' with_form_for @validating_user, :status, required: true assert_select 'input.required[required]#validating_user_status' end test 'builder input is required by default when ActiveModel::Validations is not included' do with_form_for @user, :name assert_select 'input.required[required]#user_name' end test 'builder input does not be required by default when ActiveModel::Validations is not included if option is set to false' do swap SimpleForm, required_by_default: false do with_form_for @user, :name assert_select 'input.optional#user_name' assert_no_select 'input[required]' end end test 'when not using browser validations, input does not generate required html attribute' do swap SimpleForm, browser_validations: false do with_input_for @user, :name, :string assert_select 'input[type=text].required' assert_no_select 'input[type=text][required]' end end test 'builder input allows disabling required when ActiveModel::Validations is not included' do with_form_for @user, :name, required: false assert_no_select 'input.required' assert_no_select 'input[required]' assert_select 'input.optional#user_name' end test 'when not the required component the input does not have the required attribute but has the required class' do swap_wrapper do with_input_for @user, :name, :string assert_select 'input[type=text].required' assert_no_select 'input[type=text][required]' end end # VALIDATORS :if :unless test 'builder input does not be required when ActiveModel::Validations is included and if option is present' do with_form_for @validating_user, :age assert_no_select 'input.required' assert_no_select 'input[required]' assert_select 'input.optional#validating_user_age' end test 'builder input does not be required when ActiveModel::Validations is included and unless option is present' do with_form_for @validating_user, :amount assert_no_select 'input.required' assert_no_select 'input[required]' assert_select 'input.optional#validating_user_amount' end # VALIDATORS :on test 'builder input is required when validation is on create and is not persisted' do @validating_user.new_record! with_form_for @validating_user, :action assert_select 'input.required' assert_select 'input[required]' assert_select 'input.required[required]#validating_user_action' end test 'builder input does not be required when validation is on create and is persisted' do with_form_for @validating_user, :action assert_no_select 'input.required' assert_no_select 'input[required]' assert_select 'input.optional#validating_user_action' end test 'builder input is required when validation is on save' do with_form_for @validating_user, :credit_limit assert_select 'input.required' assert_select 'input[required]' assert_select 'input.required[required]#validating_user_credit_limit' @validating_user.new_record! with_form_for @validating_user, :credit_limit assert_select 'input.required' assert_select 'input[required]' assert_select 'input.required[required]#validating_user_credit_limit' end test 'builder input is required when validation is on update and is persisted' do with_form_for @validating_user, :phone_number assert_select 'input.required' assert_select 'input[required]' assert_select 'input.required[required]#validating_user_phone_number' end test 'builder input does not be required when validation is on update and is not persisted' do @validating_user.new_record! with_form_for @validating_user, :phone_number assert_no_select 'input.required' assert_no_select 'input[required]' assert_select 'input.optional#validating_user_phone_number' end test 'builder input does not generate required html attribute when option is set to false when it is set to true in wrapper' do swap SimpleForm, browser_validations: true do swap_wrapper :default, self.custom_wrapper_with_required_input do with_concat_form_for(@user) do |f| concat f.input :name, required: false end assert_no_select 'input[type=text][required]' assert_no_select 'input[type=text][aria-required]' end end end end simple-form-3.2.0/test/inputs/datetime_input_test.rb0000644000175000017500000001443312623141213023060 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' # Tests for datetime, date and time inputs when HTML5 compatibility is enabled in the wrapper. class DateTimeInputWithHtml5Test < ActionView::TestCase test 'input generates a datetime input for datetime attributes if HTML5 compatibility is explicitly enbled' do with_input_for @user, :created_at, :datetime, html5: true assert_select 'input[type="datetime"]' end test 'input generates a datetime select for datetime attributes' do with_input_for @user, :created_at, :datetime assert_select 'select.datetime' end test 'input generates a date input for date attributes if HTML5 compatibility is explicitly enbled' do with_input_for @user, :born_at, :date, html5: true assert_select 'input[type="date"]' end test 'input generates a date select for date attributes' do with_input_for @user, :born_at, :date assert_select 'select.date' end test 'input generates a time input for time attributes if HTML5 compatibility is explicitly enbled' do with_input_for @user, :delivery_time, :time, html5: true assert_select 'input[type="time"]' end test 'input generates a time select for time attributes' do with_input_for @user, :delivery_time, :time assert_select 'select.time' end test 'input generates required html attribute' do with_input_for @user, :delivery_time, :time, required: true, html5: true assert_select 'input.required' assert_select 'input[required]' end test 'input has an aria-required html attribute' do with_input_for @user, :delivery_time, :time, required: true, html5: true assert_select 'input[aria-required=true]' end end # Tests for datetime, date and time inputs when HTML5 compatibility is enabled in the wrapper. class DateTimeInputWithoutHtml5Test < ActionView::TestCase test 'input generates a datetime select by default for datetime attributes' do swap_wrapper do with_input_for @user, :created_at, :datetime 1.upto(5) do |i| assert_select "form select.datetime#user_created_at_#{i}i" end end end test 'input is able to pass options to datetime select' do with_input_for @user, :created_at, :datetime, html5: false, disabled: true, prompt: { year: 'ano', month: 'mês', day: 'dia' } assert_select 'select.datetime[disabled=disabled]' assert_select 'select.datetime option', 'ano' assert_select 'select.datetime option', 'mês' assert_select 'select.datetime option', 'dia' end test 'input generates a datetime input for datetime attributes if HTML5 compatibility is explicitly enabled' do swap_wrapper do with_input_for @user, :created_at, :datetime, html5: true assert_select 'input[type="datetime"]' end end test 'input generates a date select for date attributes' do swap_wrapper do with_input_for @user, :born_at, :date assert_select 'select.date#user_born_at_1i' assert_select 'select.date#user_born_at_2i' assert_select 'select.date#user_born_at_3i' assert_no_select 'select.date#user_born_at_4i' end end test 'input is able to pass options to date select' do with_input_for @user, :born_at, :date, as: :date, html5: false, disabled: true, prompt: { year: 'ano', month: 'mês', day: 'dia' } assert_select 'select.date[disabled=disabled]' assert_select 'select.date option', 'ano' assert_select 'select.date option', 'mês' assert_select 'select.date option', 'dia' end test 'input is able to pass :default to date select' do with_input_for @user, :born_at, :date, default: Date.today, html5: false assert_select "select.date option[value='#{Date.today.year}'][selected=selected]" end test 'input generates a date input for date attributes if HTML5 compatibility is explicitly enabled' do swap_wrapper do with_input_for @user, :born_at, :date, html5: true assert_select 'input[type="date"]' end end test 'input generates a time select for time attributes' do swap_wrapper do with_input_for @user, :delivery_time, :time assert_select 'input[type=hidden]#user_delivery_time_1i' assert_select 'input[type=hidden]#user_delivery_time_2i' assert_select 'input[type=hidden]#user_delivery_time_3i' assert_select 'select.time#user_delivery_time_4i' assert_select 'select.time#user_delivery_time_5i' end end test 'input is able to pass options to time select' do with_input_for @user, :delivery_time, :time, required: true, html5: false, disabled: true, prompt: { hour: 'hora', minute: 'minuto' } assert_select 'select.time[disabled=disabled]' assert_select 'select.time option', 'hora' assert_select 'select.time option', 'minuto' end test 'input generates a time input for time attributes if HTML5 compatibility is explicitly enabled' do swap_wrapper do with_input_for @user, :delivery_time, :time, html5: true assert_select 'input[type="time"]' end end test 'label uses i18n to get target for date input type' do store_translations(:en, date: { order: ['month', 'day', 'year'] }) do with_input_for :project, :created_at, :date, html5: false assert_select 'label[for=project_created_at_2i]' end end test 'label uses i18n to get target for datetime input type' do store_translations(:en, date: { order: ['month', 'day', 'year'] }) do with_input_for :project, :created_at, :datetime, html5: false assert_select 'label[for=project_created_at_2i]' end end test 'label uses order to get target when date input type' do with_input_for :project, :created_at, :date, order: ['month', 'year', 'day'], html5: false assert_select 'label[for=project_created_at_2i]' end test 'label uses order to get target when datetime input type' do with_input_for :project, :created_at, :datetime, order: ['month', 'year', 'day'], html5: false assert_select 'label[for=project_created_at_2i]' end test 'label points to first option when time input type' do with_input_for :project, :created_at, :time, html5: false assert_select 'label[for=project_created_at_4i]' end test 'label points to attribute name if HTML5 compatibility is explicitly enabled' do with_input_for :project, :created_at, :date, html5: true assert_select 'label[for=project_created_at]' end end simple-form-3.2.0/test/inputs/collection_radio_buttons_input_test.rb0000644000175000017500000004144212623141213026353 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class CollectionRadioButtonsInputTest < ActionView::TestCase setup do SimpleForm::Inputs::CollectionRadioButtonsInput.reset_i18n_cache :boolean_collection end test 'input generates boolean radio buttons by default for radio types' do with_input_for @user, :active, :radio_buttons assert_select 'input[type=radio][value=true].radio_buttons#user_active_true' assert_select 'input[type=radio][value=false].radio_buttons#user_active_false' end test 'input as radio generates internal labels by default' do with_input_for @user, :active, :radio_buttons assert_select 'label[for=user_active_true]', 'Yes' assert_select 'label[for=user_active_false]', 'No' end test 'input as radio generates internal labels with accurate `for` values with nested boolean style' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons assert_select 'label[for=user_active_true]', 'Yes' assert_select 'label[for=user_active_false]', 'No' end end test 'nested label does not duplicate input id' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons, id: 'nested_id' assert_select 'input#user_active_true' assert_no_select 'label#user_active_true' end end test 'input as radio uses i18n to translate internal labels' do store_translations(:en, simple_form: { yes: 'Sim', no: 'Não' }) do with_input_for @user, :active, :radio_buttons assert_select 'label[for=user_active_true]', 'Sim' assert_select 'label[for=user_active_false]', 'Não' end end test 'input radio does not include for attribute by default' do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_select 'label' assert_no_select 'label[for=user_gender]' end test 'input radio includes for attribute when giving as html option' do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female], label_html: { for: 'gender' } assert_select 'label[for=gender]' end test 'input marks the checked value when using boolean and radios' do @user.active = false with_input_for @user, :active, :radio_buttons assert_no_select 'input[type=radio][value=true][checked]' assert_select 'input[type=radio][value=false][checked]' end test 'input allows overriding collection for radio types' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'] assert_select 'input[type=radio][value=Jose]' assert_select 'input[type=radio][value=Carlos]' assert_select 'label.collection_radio_buttons[for=user_name_jose]', 'Jose' assert_select 'label.collection_radio_buttons[for=user_name_carlos]', 'Carlos' end test 'input does automatic collection translation for radio types using defaults key' do store_translations(:en, simple_form: { options: { defaults: { gender: { male: 'Male', female: 'Female'} } } } ) do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' assert_select 'label.collection_radio_buttons[for=user_gender_male]', 'Male' assert_select 'label.collection_radio_buttons[for=user_gender_female]', 'Female' end end test 'input does automatic collection translation for radio types using specific object key' do store_translations(:en, simple_form: { options: { user: { gender: { male: 'Male', female: 'Female'} } } } ) do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' assert_select 'label.collection_radio_buttons[for=user_gender_male]', 'Male' assert_select 'label.collection_radio_buttons[for=user_gender_female]', 'Female' end end test 'input does automatic collection translation and preserve html markup' do swap SimpleForm, boolean_style: :nested do store_translations(:en, simple_form: { options: { user: { gender: { male_html: 'Male', female_html: 'Female' } } } } ) do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' assert_select 'label[for=user_gender_male] strong', 'Male' assert_select 'label[for=user_gender_female] strong', 'Female' end end end test 'input does automatic collection translation with keys prefixed with _html and a string value' do swap SimpleForm, boolean_style: :nested do store_translations(:en, simple_form: { options: { user: { gender: { male_html: 'Male', female_html: 'Female' } } } } ) do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' assert_select 'label[for=user_gender_male]', 'Male' assert_select 'label[for=user_gender_female]', 'Female' end end end test 'input marks the current radio value by default' do @user.name = "Carlos" with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'] assert_select 'input[type=radio][value=Carlos][checked=checked]' end test 'input accepts html options as the last element of collection' do with_input_for @user, :name, :radio_buttons, collection: [['Jose', 'jose', class: 'foo']] assert_select 'input.foo[type=radio][value=jose]' end test 'input allows using a collection with text/value arrays' do with_input_for @user, :name, :radio_buttons, collection: [['Jose', 'jose'], ['Carlos', 'carlos']] assert_select 'input[type=radio][value=jose]' assert_select 'input[type=radio][value=carlos]' assert_select 'label.collection_radio_buttons', 'Jose' assert_select 'label.collection_radio_buttons', 'Carlos' end test 'input allows using a collection with a Proc' do with_input_for @user, :name, :radio_buttons, collection: Proc.new { ['Jose', 'Carlos' ] } assert_select 'label.collection_radio_buttons', 'Jose' assert_select 'label.collection_radio_buttons', 'Carlos' end test 'input allows overriding only label method for collections' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'], label_method: :upcase assert_select 'label.collection_radio_buttons', 'JOSE' assert_select 'label.collection_radio_buttons', 'CARLOS' end test 'input allows overriding only value method for collections' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'], value_method: :upcase assert_select 'input[type=radio][value=JOSE]' assert_select 'input[type=radio][value=CARLOS]' end test 'input allows overriding label and value method for collections' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'], label_method: :upcase, value_method: :downcase assert_select 'input[type=radio][value=jose]' assert_select 'input[type=radio][value=carlos]' assert_select 'label.collection_radio_buttons', 'JOSE' assert_select 'label.collection_radio_buttons', 'CARLOS' end test 'input allows overriding label and value method using a lambda for collections' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'], label_method: lambda { |i| i.upcase }, value_method: lambda { |i| i.downcase } assert_select 'input[type=radio][value=jose]' assert_select 'input[type=radio][value=carlos]' assert_select 'label.collection_radio_buttons', 'JOSE' assert_select 'label.collection_radio_buttons', 'CARLOS' end test 'collection input with radio type generates required html attribute' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'] assert_select 'input[type=radio].required' assert_select 'input[type=radio][required]' end test 'collection input with radio type generates aria-required html attribute' do with_input_for @user, :name, :radio_buttons, collection: ['Jose', 'Carlos'] assert_select 'input[type=radio].required' assert_select 'input[type=radio][aria-required=true]' end test 'input radio does not wrap the collection by default' do with_input_for @user, :active, :radio_buttons assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' end test 'input radio wraps the collection in the configured collection wrapper tag' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :radio_buttons assert_select 'form ul input[type=radio]', count: 2 end end test 'input radio does not wrap the collection when configured with falsy values' do swap SimpleForm, collection_wrapper_tag: false do with_input_for @user, :active, :radio_buttons assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' end end test 'input radio allows overriding the collection wrapper tag at input level' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :radio_buttons, collection_wrapper_tag: :section assert_select 'form section input[type=radio]', count: 2 assert_no_select 'form ul' end end test 'input radio allows disabling the collection wrapper tag at input level' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :radio_buttons, collection_wrapper_tag: false assert_select 'form input[type=radio]', count: 2 assert_no_select 'form ul' end end test 'input radio renders the wrapper tag with the configured wrapper class' do swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do with_input_for @user, :active, :radio_buttons assert_select 'form ul.inputs-list input[type=radio]', count: 2 end end test 'input radio allows giving wrapper class at input level only' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :radio_buttons, collection_wrapper_class: 'items-list' assert_select 'form ul.items-list input[type=radio]', count: 2 end end test 'input radio uses both configured and given wrapper classes for wrapper tag' do swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do with_input_for @user, :active, :radio_buttons, collection_wrapper_class: 'items-list' assert_select 'form ul.inputs-list.items-list input[type=radio]', count: 2 end end test 'input radio wraps each item in the configured item wrapper tag' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :radio_buttons assert_select 'form li input[type=radio]', count: 2 end end test 'input radio does not wrap items when configured with falsy values' do swap SimpleForm, item_wrapper_tag: false do with_input_for @user, :active, :radio_buttons assert_select 'form input[type=radio]', count: 2 assert_no_select 'form li' end end test 'input radio allows overriding the item wrapper tag at input level' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :dl assert_select 'form dl input[type=radio]', count: 2 assert_no_select 'form li' end end test 'input radio allows disabling the item wrapper tag at input level' do swap SimpleForm, item_wrapper_tag: :ul do with_input_for @user, :active, :radio_buttons, item_wrapper_tag: false assert_select 'form input[type=radio]', count: 2 assert_no_select 'form li' end end test 'input radio wraps items in a span tag by default' do with_input_for @user, :active, :radio_buttons assert_select 'form span input[type=radio]', count: 2 end test 'input radio renders the item wrapper tag with a default class "radio"' do with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :li assert_select 'form li.radio input[type=radio]', count: 2 end test 'input radio renders the item wrapper tag with the configured item wrapper class' do swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do with_input_for @user, :active, :radio_buttons assert_select 'form li.radio.item input[type=radio]', count: 2 end end test 'input radio allows giving item wrapper class at input level only' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :radio_buttons, item_wrapper_class: 'item' assert_select 'form li.radio.item input[type=radio]', count: 2 end end test 'input radio uses both configured and given item wrapper classes for item wrapper tag' do swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do with_input_for @user, :active, :radio_buttons, item_wrapper_class: 'inline' assert_select 'form li.radio.item.inline input[type=radio]', count: 2 end end test 'input radio respects the nested boolean style config, generating nested label > input' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons assert_select 'span.radio > label > input#user_active_true[type=radio]' assert_select 'span.radio > label', 'Yes' assert_select 'span.radio > label > input#user_active_false[type=radio]' assert_select 'span.radio > label', 'No' assert_no_select 'label.collection_radio_buttons' end end test 'input radio with nested style does not overrides configured item wrapper tag' do swap SimpleForm, boolean_style: :nested, item_wrapper_tag: :li do with_input_for @user, :active, :radio_buttons assert_select 'li.radio > label > input' end end test 'input radio with nested style does not overrides given item wrapper tag' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons, item_wrapper_tag: :li assert_select 'li.radio > label > input' end end test 'input radio with nested style accepts giving extra wrapper classes' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons, item_wrapper_class: "inline" assert_select 'span.radio.inline > label > input' end end test 'input radio with nested style renders item labels with specified class' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :radio_buttons, item_label_class: "test" assert_select 'span.radio > label.test > input' end end test 'input radio with nested style and falsey input wrapper renders item labels with specified class' do swap SimpleForm, boolean_style: :nested, item_wrapper_tag: false do with_input_for @user, :active, :radio_buttons, item_label_class: "radio-inline" assert_select 'label.radio-inline > input' assert_no_select 'span.radio' end end test 'input radio wrapper class are not included when set to falsey' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female] assert_no_select 'label.radio' end end test 'input radio custom wrapper class is included when include input wrapper class is falsey' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_input_for @user, :gender, :radio_buttons, collection: [:male, :female], item_wrapper_class: 'custom' assert_no_select 'label.radio' assert_select 'span.custom' end end test 'input radio with nested style and namespace uses the right for attribute' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_concat_form_for @user, namespace: :foo do |f| concat f.input :gender, as: :radio_buttons, collection: [:male, :female] end assert_select 'label[for=foo_user_gender_male]' assert_select 'label[for=foo_user_gender_female]' end end test 'input radio with nested style and index uses the right for attribute' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_concat_form_for @user, index: 1 do |f| concat f.input :gender, as: :radio_buttons, collection: [:male, :female] end assert_select 'label[for=user_1_gender_male]' assert_select 'label[for=user_1_gender_female]' end end end simple-form-3.2.0/test/inputs/discovery_test.rb0000644000175000017500000000704712623141213022057 0ustar terceiroterceirorequire 'test_helper' class DiscoveryTest < ActionView::TestCase # Setup new inputs and remove them after the test. def discovery(value = false) swap SimpleForm, cache_discovery: value do begin load "support/discovery_inputs.rb" yield ensure SimpleForm::FormBuilder.discovery_cache.clear Object.send :remove_const, :StringInput Object.send :remove_const, :NumericInput Object.send :remove_const, :CustomizedInput Object.send :remove_const, :DeprecatedInput Object.send :remove_const, :CollectionSelectInput CustomInputs.send :remove_const, :PasswordInput CustomInputs.send :remove_const, :NumericInput end end end test 'builder does not discover new inputs if cached' do with_form_for @user, :name assert_select 'form input#user_name.string' discovery(true) do with_form_for @user, :name assert_no_select 'form section input#user_name.string' end end test 'builder discovers new inputs' do discovery do with_form_for @user, :name, as: :customized assert_select 'form section input#user_name.string' end end test 'builder does not discover new inputs if discovery is off' do with_form_for @user, :name assert_select 'form input#user_name.string' swap SimpleForm, inputs_discovery: false do discovery do with_form_for @user, :name assert_no_select 'form section input#user_name.string' end end end test 'builder discovers new inputs from mappings if not cached' do discovery do with_form_for @user, :name assert_select 'form section input#user_name.string' end end test 'builder discovers new inputs from internal fallbacks if not cached' do discovery do with_form_for @user, :age assert_select 'form section input#user_age.numeric.integer' end end test 'builder discovers new maped inputs from configured namespaces if not cached' do discovery do swap SimpleForm, custom_inputs_namespaces: ['CustomInputs'] do with_form_for @user, :password assert_select 'form input#user_password.password-custom-input' end end end test 'builder discovers new maped inputs from configured namespaces before the ones from top level namespace' do discovery do swap SimpleForm, custom_inputs_namespaces: ['CustomInputs'] do with_form_for @user, :age assert_select 'form input#user_age.numeric-custom-input' end end end test 'builder discovers new custom inputs from configured namespace before the ones from top level namespace' do discovery do swap SimpleForm, custom_inputs_namespaces: ['CustomInputs'] do with_form_for @user, :name, as: 'customized' assert_select 'form input#user_name.customized-namespace-custom-input' end end end test 'raises error when configured namespace does not exists' do discovery do swap SimpleForm, custom_inputs_namespaces: ['InvalidNamespace'] do assert_raise NameError do with_form_for @user, :age end end end end test 'new inputs can override the input_html_options' do discovery do with_form_for @user, :active, as: :select assert_select 'form select#user_active.select.chosen' end end test 'inputs method without wrapper_options are deprecated' do discovery do assert_deprecated do with_form_for @user, :name, as: :deprecated end assert_select 'form section input#user_name.string' end end end simple-form-3.2.0/test/inputs/collection_check_boxes_input_test.rb0000644000175000017500000002703512623141213025756 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class CollectionCheckBoxesInputTest < ActionView::TestCase setup do SimpleForm::Inputs::CollectionCheckBoxesInput.reset_i18n_cache :boolean_collection end test 'input check boxes does not include for attribute by default' do with_input_for @user, :gender, :check_boxes, collection: [:male, :female] assert_select 'label' assert_no_select 'label[for=user_gender]' end test 'input check boxes includes for attribute when giving as html option' do with_input_for @user, :gender, :check_boxes, collection: [:male, :female], label_html: { for: 'gender' } assert_select 'label[for=gender]' end test 'collection input with check_boxes type does not generate required html attribute' do with_input_for @user, :name, :check_boxes, collection: ['Jose', 'Carlos'] assert_select 'input.required' assert_no_select 'input[required]' end test 'collection input with check_boxes type does not generate aria-required html attribute' do with_input_for @user, :name, :check_boxes, collection: ['Jose', 'Carlos'] assert_select 'input.required' assert_no_select 'input[aria-required]' end test 'input does automatic collection translation for check_box types using defaults key' do store_translations(:en, simple_form: { options: { defaults: { gender: { male: 'Male', female: 'Female'} } } } ) do with_input_for @user, :gender, :check_boxes, collection: [:male, :female] assert_select 'input[type=checkbox][value=male]' assert_select 'input[type=checkbox][value=female]' assert_select 'label.collection_check_boxes', 'Male' assert_select 'label.collection_check_boxes', 'Female' end end test 'input does automatic collection translation for check_box types using specific object key' do store_translations(:en, simple_form: { options: { user: { gender: { male: 'Male', female: 'Female'} } } } ) do with_input_for @user, :gender, :check_boxes, collection: [:male, :female] assert_select 'input[type=checkbox][value=male]' assert_select 'input[type=checkbox][value=female]' assert_select 'label.collection_check_boxes', 'Male' assert_select 'label.collection_check_boxes', 'Female' end end test 'input that uses automatic collection translation for check_boxes properly sets checked values' do store_translations(:en, simple_form: { options: { defaults: { gender: { male: 'Male', female: 'Female'} } } } ) do @user.gender = 'male' with_input_for @user, :gender, :check_boxes, collection: [:male, :female] assert_select 'input[type=checkbox][value=male][checked=checked]' assert_select 'input[type=checkbox][value=female]' assert_select 'label.collection_check_boxes', 'Male' assert_select 'label.collection_check_boxes', 'Female' end end test 'input check boxes does not wrap the collection by default' do with_input_for @user, :active, :check_boxes assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' end test 'input check boxes accepts html options as the last element of collection' do with_input_for @user, :name, :check_boxes, collection: [['Jose', 'jose', class: 'foo']] assert_select 'input.foo[type=checkbox][value=jose]' end test 'input check boxes wraps the collection in the configured collection wrapper tag' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :check_boxes assert_select 'form ul input[type=checkbox]', count: 2 end end test 'input check boxes does not wrap the collection when configured with falsy values' do swap SimpleForm, collection_wrapper_tag: false do with_input_for @user, :active, :check_boxes assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' end end test 'input check boxes allows overriding the collection wrapper tag at input level' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :check_boxes, collection_wrapper_tag: :section assert_select 'form section input[type=checkbox]', count: 2 assert_no_select 'form ul' end end test 'input check boxes allows disabling the collection wrapper tag at input level' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :check_boxes, collection_wrapper_tag: false assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form ul' end end test 'input check boxes renders the wrapper tag with the configured wrapper class' do swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do with_input_for @user, :active, :check_boxes assert_select 'form ul.inputs-list input[type=checkbox]', count: 2 end end test 'input check boxes allows giving wrapper class at input level only' do swap SimpleForm, collection_wrapper_tag: :ul do with_input_for @user, :active, :check_boxes, collection_wrapper_class: 'items-list' assert_select 'form ul.items-list input[type=checkbox]', count: 2 end end test 'input check boxes uses both configured and given wrapper classes for wrapper tag' do swap SimpleForm, collection_wrapper_tag: :ul, collection_wrapper_class: 'inputs-list' do with_input_for @user, :active, :check_boxes, collection_wrapper_class: 'items-list' assert_select 'form ul.inputs-list.items-list input[type=checkbox]', count: 2 end end test 'input check boxes wraps each item in the configured item wrapper tag' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :check_boxes assert_select 'form li input[type=checkbox]', count: 2 end end test 'input check boxes does not wrap items when configured with falsy values' do swap SimpleForm, item_wrapper_tag: false do with_input_for @user, :active, :check_boxes assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form li' end end test 'input check boxes allows overriding the item wrapper tag at input level' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :check_boxes, item_wrapper_tag: :dl assert_select 'form dl input[type=checkbox]', count: 2 assert_no_select 'form li' end end test 'input check boxes allows disabling the item wrapper tag at input level' do swap SimpleForm, item_wrapper_tag: :ul do with_input_for @user, :active, :check_boxes, item_wrapper_tag: false assert_select 'form input[type=checkbox]', count: 2 assert_no_select 'form li' end end test 'input check boxes wraps items in a span tag by default' do with_input_for @user, :active, :check_boxes assert_select 'form span input[type=checkbox]', count: 2 end test 'input check boxes renders the item wrapper tag with a default class "checkbox"' do with_input_for @user, :active, :check_boxes, item_wrapper_tag: :li assert_select 'form li.checkbox input[type=checkbox]', count: 2 end test 'input check boxes renders the item wrapper tag with the configured item wrapper class' do swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do with_input_for @user, :active, :check_boxes assert_select 'form li.checkbox.item input[type=checkbox]', count: 2 end end test 'input check boxes allows giving item wrapper class at input level only' do swap SimpleForm, item_wrapper_tag: :li do with_input_for @user, :active, :check_boxes, item_wrapper_class: 'item' assert_select 'form li.checkbox.item input[type=checkbox]', count: 2 end end test 'input check boxes uses both configured and given item wrapper classes for item wrapper tag' do swap SimpleForm, item_wrapper_tag: :li, item_wrapper_class: 'item' do with_input_for @user, :active, :check_boxes, item_wrapper_class: 'inline' assert_select 'form li.checkbox.item.inline input[type=checkbox]', count: 2 end end test 'input check boxes respects the nested boolean style config, generating nested label > input' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :check_boxes assert_select 'span.checkbox > label > input#user_active_true[type=checkbox]' assert_select 'span.checkbox > label', 'Yes' assert_select 'span.checkbox > label > input#user_active_false[type=checkbox]' assert_select 'span.checkbox > label', 'No' assert_no_select 'label.collection_radio_buttons' end end test 'input check boxes with nested style does not overrides configured item wrapper tag' do swap SimpleForm, boolean_style: :nested, item_wrapper_tag: :li do with_input_for @user, :active, :check_boxes assert_select 'li.checkbox > label > input' end end test 'input check boxes with nested style does not overrides given item wrapper tag' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :check_boxes, item_wrapper_tag: :li assert_select 'li.checkbox > label > input' end end test 'input check boxes with nested style accepts giving extra wrapper classes' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :check_boxes, item_wrapper_class: "inline" assert_select 'span.checkbox.inline > label > input' end end test 'input check boxes with nested style renders item labels with specified class' do swap SimpleForm, boolean_style: :nested do with_input_for @user, :active, :check_boxes, item_label_class: "test" assert_select 'span.checkbox > label.test > input' end end test 'input check boxes with nested style and falsey input wrapper renders item labels with specified class' do swap SimpleForm, boolean_style: :nested, item_wrapper_tag: false do with_input_for @user, :active, :check_boxes, item_label_class: "checkbox-inline" assert_select 'label.checkbox-inline > input' assert_no_select 'span.checkbox' end end test 'input check boxes wrapper class are not included when set to falsey' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_input_for @user, :gender, :check_boxes, collection: [:male, :female] assert_no_select 'label.checkbox' end end test 'input check boxes custom wrapper class is included when include input wrapper class is falsey' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_input_for @user, :gender, :check_boxes, collection: [:male, :female], item_wrapper_class: 'custom' assert_no_select 'label.checkbox' assert_select 'span.custom' end end test 'input check boxes with nested style and namespace uses the right for attribute' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_concat_form_for @user, namespace: :foo do |f| concat f.input :gender, as: :check_boxes, collection: [:male, :female] end assert_select 'label[for=foo_user_gender_male]' assert_select 'label[for=foo_user_gender_female]' end end test 'input check boxes with nested style and index uses the right for attribute' do swap SimpleForm, include_default_input_wrapper_class: false, boolean_style: :nested do with_concat_form_for @user, index: 1 do |f| concat f.input :gender, as: :check_boxes, collection: [:male, :female] end assert_select 'label[for=user_1_gender_male]' assert_select 'label[for=user_1_gender_female]' end end end simple-form-3.2.0/test/inputs/general_test.rb0000644000175000017500000001151612623141213021461 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class InputTest < ActionView::TestCase test 'input generates css class based on default input type' do with_input_for @user, :name, :string assert_select 'input.string' with_input_for @user, :description, :text assert_select 'textarea.text' with_input_for @user, :age, :integer assert_select 'input.integer' with_input_for @user, :born_at, :date assert_select 'select.date' with_input_for @user, :created_at, :datetime assert_select 'select.datetime' end test 'string input generates autofocus attribute when autofocus option is true' do with_input_for @user, :name, :string, autofocus: true assert_select 'input.string[autofocus]' end test 'input accepts input_class configuration' do swap SimpleForm, input_class: :xlarge do with_input_for @user, :name, :string assert_select 'input.xlarge' assert_no_select 'div.xlarge' end end test 'input does not add input_class when configured to not generate additional classes for input' do swap SimpleForm, input_class: 'xlarge', generate_additional_classes_for: [:wrapper] do with_input_for @user, :name, :string assert_select 'input' assert_no_select '.xlarge' end end test 'text input generates autofocus attribute when autofocus option is true' do with_input_for @user, :description, :text, autofocus: true assert_select 'textarea.text[autofocus]' end test 'numeric input generates autofocus attribute when autofocus option is true' do with_input_for @user, :age, :integer, autofocus: true assert_select 'input.integer[autofocus]' end test 'date input generates autofocus attribute when autofocus option is true' do with_input_for @user, :born_at, :date, autofocus: true assert_select 'select.date[autofocus]' end test 'datetime input generates autofocus attribute when autofocus option is true' do with_input_for @user, :created_at, :datetime, autofocus: true assert_select 'select.datetime[autofocus]' end test 'string input generates autofocus attribute when autofocus option is false' do with_input_for @user, :name, :string, autofocus: false assert_no_select 'input.string[autofocus]' end test 'text input generates autofocus attribute when autofocus option is false' do with_input_for @user, :description, :text, autofocus: false assert_no_select 'textarea.text[autofocus]' end test 'numeric input generates autofocus attribute when autofocus option is false' do with_input_for @user, :age, :integer, autofocus: false assert_no_select 'input.integer[autofocus]' end test 'date input generates autofocus attribute when autofocus option is false' do with_input_for @user, :born_at, :date, autofocus: false assert_no_select 'select.date[autofocus]' end test 'datetime input generates autofocus attribute when autofocus option is false' do with_input_for @user, :created_at, :datetime, autofocus: false assert_no_select 'select.datetime[autofocus]' end test 'string input generates autofocus attribute when autofocus option is not present' do with_input_for @user, :name, :string assert_no_select 'input.string[autofocus]' end test 'text input generates autofocus attribute when autofocus option is not present' do with_input_for @user, :description, :text assert_no_select 'textarea.text[autofocus]' end test 'numeric input generates autofocus attribute when autofocus option is not present' do with_input_for @user, :age, :integer assert_no_select 'input.integer[autofocus]' end test 'date input generates autofocus attribute when autofocus option is not present' do with_input_for @user, :born_at, :date assert_no_select 'select.date[autofocus]' end test 'datetime input generates autofocus attribute when autofocus option is not present' do with_input_for @user, :created_at, :datetime assert_no_select 'select.datetime[autofocus]' end # With no object test 'input is generated properly when object is not present' do with_input_for :project, :name, :string assert_select 'input.string.required#project_name' end test 'input as radio is generated properly when object is not present ' do with_input_for :project, :name, :radio_buttons assert_select 'input.radio_buttons#project_name_true' assert_select 'input.radio_buttons#project_name_false' end test 'input as select with collection is generated properly when object is not present' do with_input_for :project, :name, :select, collection: ['Jose', 'Carlos'] assert_select 'select.select#project_name' end test 'input does not generate empty css class' do swap SimpleForm, generate_additional_classes_for: [:wrapper, :label] do with_input_for :project, :name, :string assert_no_select 'input#project_name[class]' end end end simple-form-3.2.0/test/inputs/hidden_input_test.rb0000644000175000017500000000172312623141213022515 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class HiddenInputTest < ActionView::TestCase test 'input generates a hidden field' do with_input_for @user, :name, :hidden assert_no_select 'input[type=text]' assert_select 'input#user_name[type=hidden]' end test 'hint does not be generated for hidden fields' do store_translations(:en, simple_form: { hints: { user: { name: "text" } } }) do with_input_for @user, :name, :hidden assert_no_select 'span.hint' end end test 'label does not be generated for hidden inputs' do with_input_for @user, :name, :hidden assert_no_select 'label' end test 'required/aria-required/optional options does not be generated for hidden inputs' do with_input_for @user, :name, :hidden assert_no_select 'input.required' assert_no_select 'input[required]' assert_no_select 'input[aria-required]' assert_no_select 'input.optional' assert_select 'input.hidden#user_name' end end simple-form-3.2.0/test/inputs/file_input_test.rb0000644000175000017500000000074412623141213022203 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class FileInputTest < ActionView::TestCase test 'input generates a file field' do with_input_for @user, :name, :file assert_select 'input#user_name[type=file]' end test "input generates a file field that doesn't accept placeholder" do store_translations(:en, simple_form: { placeholders: { user: { name: "text" } } }) do with_input_for @user, :name, :file assert_no_select 'input[placeholder]' end end end simple-form-3.2.0/test/inputs/grouped_collection_select_input_test.rb0000644000175000017500000001353512623141213026505 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class GroupedCollectionSelectInputTest < ActionView::TestCase test 'grouped collection accepts array collection form' do with_input_for @user, :tag_ids, :grouped_select, collection: [['Authors', ['Jose', 'Carlos']], ['General', ['Bob', 'John']]], group_method: :last assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option', 'Jose' assert_select 'option', 'Carlos' end assert_select 'optgroup[label=General]' do assert_select 'option', 'Bob' assert_select 'option', 'John' end end end test 'grouped collection accepts empty array collection form' do with_input_for @user, :tag_ids, :grouped_select, collection: [], group_method: :last assert_select 'select.grouped_select#user_tag_ids' end test 'grouped collection accepts proc as collection' do with_input_for @user, :tag_ids, :grouped_select, collection: Proc.new { [['Authors', ['Jose', 'Carlos']], ['General', ['Bob', 'John']]] }, group_method: :last assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option', 'Jose' assert_select 'option', 'Carlos' end assert_select 'optgroup[label=General]' do assert_select 'option', 'Bob' assert_select 'option', 'John' end end end test 'grouped collection accepts hash collection form' do with_input_for @user, :tag_ids, :grouped_select, collection: { 'Authors' => ['Jose', 'Carlos'], 'General' => ['Bob', 'John'] }, group_method: :last assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option', 'Jose' assert_select 'option', 'Carlos' end assert_select 'optgroup[label=General]' do assert_select 'option', 'Bob' assert_select 'option', 'John' end end end test 'grouped collection accepts group_label_method option' do with_input_for @user, :tag_ids, :grouped_select, collection: { ['Jose', 'Carlos'] => 'Authors' }, group_method: :first, group_label_method: :last assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option', 'Jose' assert_select 'option', 'Carlos' end end end test 'grouped collection finds default label methods on the group objects' do option_list = ['Jose', 'Carlos'] GroupedClass = Struct.new(:to_label, :options) group = GroupedClass.new("Authors", option_list) with_input_for @user, :tag_ids, :grouped_select, collection: [group], group_method: :options assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option', 'Jose' assert_select 'option', 'Carlos' end end end test 'grouped collections finds the default label method from the first non-empty object' do Agent = Struct.new(:id, :name) agents = [["First", []], ["Second", [Agent.new(7, 'Bond'), Agent.new(47, 'Hitman')]]] with_input_for @user, :tag_ids, :grouped_select, collection: agents, group_label_method: :first, group_method: :last, include_blank: false assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Second]' do assert_select 'option[value="7"]', 'Bond' assert_select 'option[value="47"]', 'Hitman' end end end test 'grouped collection accepts label and value methods options' do with_input_for @user, :tag_ids, :grouped_select, collection: { 'Authors' => ['Jose', 'Carlos'] }, group_method: :last, label_method: :upcase, value_method: :downcase assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option[value=jose]', 'JOSE' assert_select 'option[value=carlos]', 'CARLOS' end end end test 'grouped collection allows overriding label and value methods using a lambda' do with_input_for @user, :tag_ids, :grouped_select, collection: { 'Authors' => ['Jose', 'Carlos'] }, group_method: :last, label_method: lambda { |i| i.upcase }, value_method: lambda { |i| i.downcase } assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option[value=jose]', 'JOSE' assert_select 'option[value=carlos]', 'CARLOS' end end end test 'grouped collection with associations' do tag_groups = [ TagGroup.new(1, "Group of Tags", [Tag.new(1, "Tag 1"), Tag.new(2, "Tag 2")]), TagGroup.new(2, "Other group", [Tag.new(3, "Tag 3"), Tag.new(4,"Tag 4")]) ] with_input_for @user, :tag_ids, :grouped_select, collection: tag_groups, group_method: :tags assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label="Group of Tags"]' do assert_select 'option[value="1"]', 'Tag 1' assert_select 'option[value="2"]', 'Tag 2' end assert_select 'optgroup[label="Other group"]' do assert_select 'option[value="3"]', 'Tag 3' assert_select 'option[value="4"]', 'Tag 4' end end end test 'grouped collection accepts html options as the last element of collection' do with_input_for @user, :tag_ids, :grouped_select, collection: [['Authors', [['Jose', 'jose', class: 'foo'], ['Carlos', 'carlos', class: 'bar']]]], group_method: :last assert_select 'select.grouped_select#user_tag_ids' do assert_select 'optgroup[label=Authors]' do assert_select 'option.foo', 'Jose' assert_select 'option.bar', 'Carlos' end end end end simple-form-3.2.0/test/inputs/priority_input_test.rb0000644000175000017500000000346312623141213023146 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class PriorityInputTest < ActionView::TestCase test 'input generates a country select field' do with_input_for @user, :country, :country assert_select 'select#user_country' assert_select 'select option[value=Brazil]', 'Brazil' assert_no_select 'select option[value=""][disabled=disabled]' end test 'input generates a country select with SimpleForm default' do swap SimpleForm, country_priority: [ 'Brazil' ] do with_input_for @user, :country, :country assert_select 'select option[value=""][disabled=disabled]' end end test 'input generates a time zone select field' do with_input_for @user, :time_zone, :time_zone assert_select 'select#user_time_zone' assert_select 'select option[value=Brasilia]', '(GMT-03:00) Brasilia' assert_no_select 'select option[value=""][disabled=disabled]' end test 'input generates a time zone select field with default' do with_input_for @user, :time_zone, :time_zone, default: 'Brasilia' assert_select 'select option[value=Brasilia][selected=selected]' assert_no_select 'select option[value=""]' end test 'input generates a time zone select using options priority' do with_input_for @user, :time_zone, :time_zone, priority: /Brasilia/ assert_select 'select option[value=""][disabled=disabled]' assert_no_select 'select option[value=""]', /^$/ end test 'priority input does not generate invalid required html attribute' do with_input_for @user, :country, :country assert_select 'select.required' assert_no_select 'select[required]' end test 'priority input does not generate invalid aria-required html attribute' do with_input_for @user, :country, :country assert_select 'select.required' assert_no_select 'select[aria-required]' end end simple-form-3.2.0/test/inputs/numeric_input_test.rb0000644000175000017500000001355212623141213022727 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class NumericInputTest < ActionView::TestCase test 'input generates an integer text field for integer attributes ' do with_input_for @user, :age, :integer assert_select 'input[type=number].integer#user_age' end test 'input generates a float text field for float attributes ' do with_input_for @user, :age, :float assert_select 'input[type=number].float#user_age' end test 'input generates a decimal text field for decimal attributes ' do with_input_for @user, :age, :decimal assert_select 'input[type=number].decimal#user_age' end test 'input does not generate min attribute by default' do with_input_for @user, :age, :integer assert_no_select 'input[min]' end test 'input does not generate max attribute by default' do with_input_for @user, :age, :integer assert_no_select 'input[max]' end test 'input infers min value from integer attributes with greater than validation' do with_input_for @other_validating_user, :age, :float assert_no_select 'input[min]' with_input_for @other_validating_user, :age, :integer assert_select 'input[min="18"]' end test 'input infers min value from integer attributes with greater than validation using symbol' do with_input_for @validating_user, :amount, :float assert_no_select 'input[min]' with_input_for @validating_user, :amount, :integer assert_select 'input[min="11"]' end test 'input infers min value from integer attributes with greater than or equal to validation using symbol' do with_input_for @validating_user, :attempts, :float assert_select 'input[min="1"]' with_input_for @validating_user, :attempts, :integer assert_select 'input[min="1"]' end test 'input infers min value from integer attributes with greater than validation using proc' do with_input_for @other_validating_user, :amount, :float assert_no_select 'input[min]' with_input_for @other_validating_user, :amount, :integer assert_select 'input[min="20"]' end test 'input infers min value from integer attributes with greater than or equal to validation using proc' do with_input_for @other_validating_user, :attempts, :float assert_select 'input[min="19"]' with_input_for @other_validating_user, :attempts, :integer assert_select 'input[min="19"]' end test 'input infers max value from attributes with less than validation' do with_input_for @other_validating_user, :age, :float assert_no_select 'input[max]' with_input_for @other_validating_user, :age, :integer assert_select 'input[max="99"]' end test 'input infers max value from attributes with less than validation using symbol' do with_input_for @validating_user, :amount, :float assert_no_select 'input[max]' with_input_for @validating_user, :amount, :integer assert_select 'input[max="99"]' end test 'input infers max value from attributes with less than or equal to validation using symbol' do with_input_for @validating_user, :attempts, :float assert_select 'input[max="100"]' with_input_for @validating_user, :attempts, :integer assert_select 'input[max="100"]' end test 'input infers max value from attributes with less than validation using proc' do with_input_for @other_validating_user, :amount, :float assert_no_select 'input[max]' with_input_for @other_validating_user, :amount, :integer assert_select 'input[max="118"]' end test 'input infers max value from attributes with less than or equal to validation using proc' do with_input_for @other_validating_user, :attempts, :float assert_select 'input[max="119"]' with_input_for @other_validating_user, :attempts, :integer assert_select 'input[max="119"]' end test 'input has step value of any except for integer attribute' do with_input_for @validating_user, :age, :float assert_select 'input[step="any"]' with_input_for @validating_user, :age, :integer assert_select 'input[step="1"]' end test 'numeric input does not generate placeholder by default' do with_input_for @user, :age, :integer assert_no_select 'input[placeholder]' end test 'numeric input accepts the placeholder option' do with_input_for @user, :age, :integer, placeholder: 'Put in your age' assert_select 'input.integer[placeholder="Put in your age"]' end test 'numeric input uses i18n to translate placeholder text' do store_translations(:en, simple_form: { placeholders: { user: { age: 'Age goes here' } } }) do with_input_for @user, :age, :integer assert_select 'input.integer[placeholder="Age goes here"]' end end # Numeric input but HTML5 disabled test 'when not using HTML5 input does not generate field with type number and use text instead' do swap_wrapper do with_input_for @user, :age, :integer assert_no_select "input[type=number]" assert_no_select "input#user_age[text]" end end test 'when not using HTML5 input does not use min or max or step attributes' do swap_wrapper do with_input_for @validating_user, :age, :integer assert_no_select "input[type=number]" assert_no_select "input[min]" assert_no_select "input[max]" assert_no_select "input[step]" end end [:integer, :float, :decimal].each do |type| test "#{type} input infers min value from attributes with greater than or equal validation" do with_input_for @validating_user, :age, type assert_select 'input[min="18"]' end test "#{type} input infers the max value from attributes with less than or equal to validation" do with_input_for @validating_user, :age, type assert_select 'input[max="99"]' end end test 'min_max does not emit max value as bare string' do with_input_for @other_validating_user, :age, :integer assert_select 'input[max]' assert_no_select 'div', %r{^99} end end simple-form-3.2.0/test/inputs/collection_select_input_test.rb0000644000175000017500000004026512623141213024760 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class CollectionSelectInputTest < ActionView::TestCase setup do SimpleForm::Inputs::CollectionSelectInput.reset_i18n_cache :boolean_collection end test 'input generates a boolean select with options by default for select types' do with_input_for @user, :active, :select assert_select 'select.select#user_active' assert_select 'select option[value=true]', 'Yes' assert_select 'select option[value=false]', 'No' end test 'input as select uses i18n to translate select boolean options' do store_translations(:en, simple_form: { yes: 'Sim', no: 'Não' }) do with_input_for @user, :active, :select assert_select 'select option[value=true]', 'Sim' assert_select 'select option[value=false]', 'Não' end end test 'input allows overriding collection for select types' do with_input_for @user, :name, :select, collection: ['Jose', 'Carlos'] assert_select 'select.select#user_name' assert_select 'select option', 'Jose' assert_select 'select option', 'Carlos' end test 'input does automatic collection translation for select types using defaults key' do store_translations(:en, simple_form: { options: { defaults: { gender: { male: 'Male', female: 'Female'} } } }) do with_input_for @user, :gender, :select, collection: [:male, :female] assert_select 'select.select#user_gender' assert_select 'select option', 'Male' assert_select 'select option', 'Female' end end test 'input does automatic collection translation for select types using specific object key' do store_translations(:en, simple_form: { options: { user: { gender: { male: 'Male', female: 'Female'} } } }) do with_input_for @user, :gender, :select, collection: [:male, :female] assert_select 'select.select#user_gender' assert_select 'select option', 'Male' assert_select 'select option', 'Female' end end test 'input marks the selected value by default' do @user.name = "Carlos" with_input_for @user, :name, :select, collection: ['Jose', 'Carlos'] assert_select 'select option[selected=selected]', 'Carlos' end test 'input accepts html options as the last element of collection' do with_input_for @user, :name, :select, collection: [['Jose', class: 'foo']] assert_select 'select.select#user_name' assert_select 'select option.foo', 'Jose' end test 'input marks the selected value also when using integers' do @user.age = 18 with_input_for @user, :age, :select, collection: 18..60 assert_select 'select option[selected=selected]', '18' end test 'input marks the selected value when using booleans and select' do @user.active = false with_input_for @user, :active, :select assert_no_select 'select option[selected][value=true]', 'Yes' assert_select 'select option[selected][value=false]', 'No' end test 'input sets the correct value when using a collection that includes floats' do with_input_for @user, :age, :select, collection: [2.0, 2.5, 3.0, 3.5, 4.0, 4.5] assert_select 'select option[value="2.0"]' assert_select 'select option[value="2.5"]' end test 'input sets the correct values when using a collection that uses mixed values' do with_input_for @user, :age, :select, collection: ["Hello Kitty", 2, 4.5, :johnny, nil, true, false] assert_select 'select option[value="Hello Kitty"]' assert_select 'select option[value="2"]' assert_select 'select option[value="4.5"]' assert_select 'select option[value="johnny"]' assert_select 'select option[value=""]' assert_select 'select option[value="true"]' assert_select 'select option[value="false"]' end test 'input includes a blank option even if :include_blank is set to false if the collection includes a nil value' do with_input_for @user, :age, :select, collection: [nil], include_blank: false assert_select 'select option[value=""]' end test 'input automatically sets include blank' do with_input_for @user, :age, :select, collection: 18..30 assert_select 'select option[value=""]', '' end test 'input translates include blank when set to :translate' do store_translations(:en, simple_form: { include_blanks: { user: { age: 'Rather not say' } } }) do with_input_for @user, :age, :select, collection: 18..30, include_blank: :translate assert_select 'select option[value=""]', 'Rather not say' end end test 'input translates include blank with a default' do store_translations(:en, simple_form: { include_blanks: { defaults: { age: 'Rather not say', } } }) do with_input_for @user, :age, :select, collection: 18..30, include_blank: :translate assert_select 'select option[value=""]', 'Rather not say' end end test 'input does not translate include blank when set to a string' do store_translations(:en, simple_form: { include_blanks: { user: { age: 'Rather not say' } } }) do with_input_for @user, :age, :select, collection: 18..30, include_blank: 'Young at heart' assert_select 'select option[value=""]', 'Young at heart' end end test 'input does not translate include blank when automatically set' do store_translations(:en, simple_form: { include_blanks: { user: { age: 'Rather not say' } } }) do with_input_for @user, :age, :select, collection: 18..30 assert_select 'select option[value=""]', '' end end test 'input does not translate include blank when set to true' do store_translations(:en, simple_form: { include_blanks: { user: { age: 'Rather not say' } } }) do with_input_for @user, :age, :select, collection: 18..30, include_blank: true assert_select 'select option[value=""]', '' end end test 'input does not translate include blank when set to false' do store_translations(:en, simple_form: { include_blanks: { user: { age: 'Rather not say' } } }) do with_input_for @user, :age, :select, collection: 18..30, include_blank: false assert_no_select 'select option[value=""]' end end test 'input does not set include blank if otherwise is told' do with_input_for @user, :age, :select, collection: 18..30, include_blank: false assert_no_select 'select option[value=""]' end test 'input does not set include blank if prompt is given' do with_input_for @user, :age, :select, collection: 18..30, prompt: "Please select foo" assert_no_select 'select option[value=""]', '' end test 'input does not set include blank if multiple is given' do with_input_for @user, :age, :select, collection: 18..30, input_html: { multiple: true } assert_no_select 'select option[value=""]', '' end test 'input translates prompt when set to :translate' do store_translations(:en, simple_form: { prompts: { user: { age: 'Select age:' } } }) do with_input_for @user, :age, :select, collection: 18..30, prompt: :translate assert_select 'select option[value=""]', 'Select age:' end end test 'input translates prompt with a default' do store_translations(:en, simple_form: { prompts: { defaults: { age: 'Select age:', } } }) do with_input_for @user, :age, :select, collection: 18..30, prompt: :translate assert_select 'select option[value=""]', 'Select age:' end end test 'input does not translate prompt when set to a string' do store_translations(:en, simple_form: { prompts: { user: { age: 'Select age:' } } }) do with_input_for @user, :age, :select, collection: 18..30, prompt: 'Do it:' assert_select 'select option[value=""]', 'Do it:' end end test 'input does not translate prompt when set to false' do store_translations(:en, simple_form: { prompts: { user: { age: 'Select age:' } } }) do with_input_for @user, :age, :select, collection: 18..30, prompt: false assert_no_select 'select option[value=""]' end end test 'input uses Rails prompt translation as a fallback' do store_translations(:en, helpers: { select: { prompt: 'Select value:' } }) do with_input_for @user, :age, :select, collection: 18..30, prompt: :translate assert_select 'select option[value=""]', "Select value:" end end test 'input detects label and value on collections' do users = [User.build(id: 1, name: "Jose"), User.build(id: 2, name: "Carlos")] with_input_for @user, :description, :select, collection: users assert_select 'select option[value="1"]', 'Jose' assert_select 'select option[value="2"]', 'Carlos' end test 'input disables the anothers components when the option is a object' do with_input_for @user, :description, :select, collection: ["Jose", "Carlos"], disabled: true assert_no_select 'select option[value=Jose][disabled=disabled]', 'Jose' assert_no_select 'select option[value=Carlos][disabled=disabled]', 'Carlos' assert_select 'select[disabled=disabled]' assert_select 'div.disabled' end test 'input does not disable the anothers components when the option is a object' do with_input_for @user, :description, :select, collection: ["Jose", "Carlos"], disabled: 'Jose' assert_select 'select option[value=Jose][disabled=disabled]', 'Jose' assert_no_select 'select option[value=Carlos][disabled=disabled]', 'Carlos' assert_no_select 'select[disabled=disabled]' assert_no_select 'div.disabled' end test 'input allows overriding label and value method using a lambda for collection selects' do with_input_for @user, :name, :select, collection: ['Jose', 'Carlos'], label_method: lambda { |i| i.upcase }, value_method: lambda { |i| i.downcase } assert_select 'select option[value=jose]', "JOSE" assert_select 'select option[value=carlos]', "CARLOS" end test 'input allows overriding only label but not value method using a lambda for collection select' do with_input_for @user, :name, :select, collection: ['Jose', 'Carlos'], label_method: lambda { |i| i.upcase } assert_select 'select option[value=Jose]', "JOSE" assert_select 'select option[value=Carlos]', "CARLOS" end test 'input allows overriding only value but not label method using a lambda for collection select' do with_input_for @user, :name, :select, collection: ['Jose', 'Carlos'], value_method: lambda { |i| i.downcase } assert_select 'select option[value=jose]', "Jose" assert_select 'select option[value=carlos]', "Carlos" end test 'input allows symbols for collections' do with_input_for @user, :name, :select, collection: [:jose, :carlos] assert_select 'select.select#user_name' assert_select 'select option[value=jose]', 'jose' assert_select 'select option[value=carlos]', 'carlos' end test 'collection input with select type generates required html attribute only with blank option' do with_input_for @user, :name, :select, include_blank: true, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[required]' end test 'collection input with select type generates required html attribute only with blank option or prompt' do with_input_for @user, :name, :select, prompt: 'Name...', collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[required]' end test 'collection input with select type does not generate required html attribute without blank option' do with_input_for @user, :name, :select, include_blank: false, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_no_select 'select[required]' assert_no_select 'select[aria-required=true]' end test 'collection input with select type with multiple attribute generates required html attribute without blank option' do with_input_for @user, :name, :select, include_blank: false, input_html: { multiple: true }, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[required]' end test 'collection input with select type with multiple attribute generates required html attribute with blank option' do with_input_for @user, :name, :select, include_blank: true, input_html: { multiple: true }, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[required]' end test 'with a blank option, a collection input of type select has an aria-required html attribute' do with_input_for @user, :name, :select, include_blank: true, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[aria-required=true]' end test 'without a blank option, a collection input of type select does not have an aria-required html attribute' do with_input_for @user, :name, :select, include_blank: false, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_no_select 'select[aria-required]' end test 'without a blank option and with a multiple option, a collection input of type select has an aria-required html attribute' do with_input_for @user, :name, :select, include_blank: false, input_html: { multiple: true }, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[aria-required=true]' end test 'with a blank option and a multiple option, a collection input of type select has an aria-required html attribute' do with_input_for @user, :name, :select, include_blank: true, input_html: { multiple: true }, collection: ['Jose', 'Carlos'] assert_select 'select.required' assert_select 'select[aria-required]' end test 'input allows disabled options with a lambda for collection select' do with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], disabled: lambda { |x| x == "Carlos" } assert_select 'select option[value=Carlos][disabled=disabled]', 'Carlos' assert_select 'select option[value=Antonio]', 'Antonio' assert_no_select 'select option[value=Antonio][disabled]' end test 'input allows disabled and label method with lambdas for collection select' do with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], disabled: lambda { |x| x == "Carlos" }, label_method: lambda { |x| x.upcase } assert_select 'select option[value=Carlos][disabled=disabled]', 'CARLOS' assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][disabled]' end test 'input allows a non lambda disabled option with lambda label method for collections' do with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], disabled: "Carlos", label_method: lambda { |x| x.upcase } assert_select 'select option[value=Carlos][disabled=disabled]', 'CARLOS' assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][disabled]' end test 'input allows selected and label method with lambdas for collection select' do with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], selected: lambda { |x| x == "Carlos" }, label_method: lambda { |x| x.upcase } assert_select 'select option[value=Carlos][selected=selected]', 'CARLOS' assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][selected]' end test 'input allows a non lambda selected option with lambda label method for collection select' do with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], selected: "Carlos", label_method: lambda { |x| x.upcase } assert_select 'select option[value=Carlos][selected=selected]', 'CARLOS' assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][selected]' end test 'input does not override default selection through attribute value with label method as lambda for collection select' do @user.name = "Carlos" with_input_for @user, :name, :select, collection: ["Carlos", "Antonio"], label_method: lambda { |x| x.upcase } assert_select 'select option[value=Carlos][selected=selected]', 'CARLOS' assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][selected]' end end simple-form-3.2.0/test/inputs/readonly_test.rb0000644000175000017500000000766612623141213021674 0ustar terceiroterceirorequire 'test_helper' class ReadonlyTest < ActionView::TestCase test 'string input generates readonly elements when readonly option is true' do with_input_for @user, :name, :string, readonly: true assert_select 'input.string.readonly[readonly]' end test 'text input generates readonly elements when readonly option is true' do with_input_for @user, :description, :text, readonly: true assert_select 'textarea.text.readonly[readonly]' end test 'numeric input generates readonly elements when readonly option is true' do with_input_for @user, :age, :integer, readonly: true assert_select 'input.integer.readonly[readonly]' end test 'date input generates readonly elements when readonly option is true' do with_input_for @user, :born_at, :date, readonly: true assert_select 'select.date.readonly[readonly]' end test 'datetime input generates readonly elements when readonly option is true' do with_input_for @user, :created_at, :datetime, readonly: true assert_select 'select.datetime.readonly[readonly]' end test 'string input generates readonly elements when readonly option is false' do with_input_for @user, :name, :string, readonly: false assert_no_select 'input.string.readonly[readonly]' end test 'text input generates readonly elements when readonly option is false' do with_input_for @user, :description, :text, readonly: false assert_no_select 'textarea.text.readonly[readonly]' end test 'numeric input generates readonly elements when readonly option is false' do with_input_for @user, :age, :integer, readonly: false assert_no_select 'input.integer.readonly[readonly]' end test 'date input generates readonly elements when readonly option is false' do with_input_for @user, :born_at, :date, readonly: false assert_no_select 'select.date.readonly[readonly]' end test 'datetime input generates readonly elements when readonly option is false' do with_input_for @user, :created_at, :datetime, readonly: false assert_no_select 'select.datetime.readonly[readonly]' end test 'string input generates readonly elements when readonly option is not present' do with_input_for @user, :name, :string assert_no_select 'input.string.readonly[readonly]' end test 'text input generates readonly elements when readonly option is not present' do with_input_for @user, :description, :text assert_no_select 'textarea.text.readonly[readonly]' end test 'numeric input generates readonly elements when readonly option is not present' do with_input_for @user, :age, :integer assert_no_select 'input.integer.readonly[readonly]' end test 'date input generates readonly elements when readonly option is not present' do with_input_for @user, :born_at, :date assert_no_select 'select.date.readonly[readonly]' end test 'datetime input generates readonly elements when readonly option is not present' do with_input_for @user, :created_at, :datetime assert_no_select 'select.datetime.readonly[readonly]' end test 'input generates readonly attribute when the field is readonly and the object is persisted' do with_input_for @user, :credit_card, :string, readonly: :lookup assert_select 'input.string.readonly[readonly]' end test 'input does not generate readonly attribute when the field is readonly and the object is not persisted' do @user.new_record! with_input_for @user, :credit_card, :string, readonly: :lookup assert_no_select 'input.string.readonly[readonly]' end test 'input does not generate readonly attribute when the field is not readonly and the object is persisted' do with_input_for @user, :name, :string assert_no_select 'input.string.readonly[readonly]' end test 'input does not generate readonly attribute when the component is not used' do swap_wrapper do with_input_for @user, :credit_card, :string assert_no_select 'input.string.readonly[readonly]' end end end simple-form-3.2.0/test/inputs/string_input_test.rb0000644000175000017500000001244712623141213022575 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class StringInputTest < ActionView::TestCase test 'input maps text field to string attribute' do with_input_for @user, :name, :string assert_select "input#user_name[type=text][name='user[name]'][value='New in SimpleForm!']" end test 'input generates a password field for password attributes' do with_input_for @user, :password, :password assert_select "input#user_password.password[type=password][name='user[password]']" end test 'input gets maxlength from column definition for string attributes' do with_input_for @user, :name, :string assert_select 'input.string[maxlength="100"]' end test 'input does not get maxlength from column without size definition for string attributes' do with_input_for @user, :action, :string assert_no_select 'input.string[maxlength]' end test 'input gets maxlength from column definition for password attributes' do with_input_for @user, :password, :password assert_select 'input.password[type=password][maxlength="100"]' end test 'input infers maxlength column definition from validation when present' do with_input_for @validating_user, :name, :string assert_select 'input.string[maxlength="25"]' end test 'input does not get maxlength from validation when tokenizer present' do with_input_for @validating_user, :action, :string assert_no_select 'input.string[maxlength]' end test 'input gets maxlength from validation when :is option present' do with_input_for @validating_user, :home_picture, :string assert_select 'input.string[maxlength="12"]' end test 'input maxlength is the column limit plus one to make room for decimal point' do with_input_for @user, :credit_limit, :string assert_select 'input.string[maxlength="16"]' end test 'input does not generate placeholder by default' do with_input_for @user, :name, :string assert_no_select 'input[placeholder]' end test 'input accepts the placeholder option' do with_input_for @user, :name, :string, placeholder: 'Put in some text' assert_select 'input.string[placeholder="Put in some text"]' end test 'input generates a password field for password attributes that accept placeholder' do with_input_for @user, :password, :password, placeholder: 'Password Confirmation' assert_select 'input[type=password].password[placeholder="Password Confirmation"]#user_password' end test 'input does not infer pattern from attributes by default' do with_input_for @other_validating_user, :country, :string assert_no_select 'input[pattern="\w+"]' end test 'input infers pattern from attributes' do with_input_for @other_validating_user, :country, :string, pattern: true assert_select 'input[pattern="\w+"]' end test 'input infers pattern from attributes using proc' do with_input_for @other_validating_user, :name, :string, pattern: true assert_select 'input[pattern="\w+"]' end test 'input does not infer pattern from attributes if root default is false' do swap_wrapper do with_input_for @other_validating_user, :country, :string assert_no_select 'input[pattern="\w+"]' end end test 'input uses given pattern from attributes' do with_input_for @other_validating_user, :country, :string, input_html: { pattern: "\\d+" } assert_select 'input[pattern="\d+"]' end test 'input does not use pattern if model has :without validation option' do with_input_for @other_validating_user, :description, :string, pattern: true assert_no_select 'input[pattern="\d+"]' end test 'input uses i18n to translate placeholder text' do store_translations(:en, simple_form: { placeholders: { user: { name: 'Name goes here' } } }) do with_input_for @user, :name, :string assert_select 'input.string[placeholder="Name goes here"]' end end test 'input uses custom i18n scope to translate placeholder text' do store_translations(:en, my_scope: { placeholders: { user: { name: 'Name goes here' } } }) do swap SimpleForm, i18n_scope: :my_scope do with_input_for @user, :name, :string assert_select 'input.string[placeholder="Name goes here"]' end end end [:email, :url, :search, :tel].each do |type| test "input allows type #{type}" do with_input_for @user, :name, type assert_select "input.string.#{type}" assert_select "input[type=#{type}]" end test "input does not allow type #{type} if HTML5 compatibility is disabled" do swap_wrapper do with_input_for @user, :name, type assert_select "input[type=text]" assert_no_select "input[type=#{type}]" end end end test 'input strips extra spaces from class html attribute with default classes' do with_input_for @user, :name, :string assert_select "input[class='string required']" assert_no_select "input[class='string required ']" assert_no_select "input[class=' string required']" end test 'input strips extra spaces from class html attribute when giving a custom class' do with_input_for @user, :name, :string, input_html: { class: "my_input" } assert_select "input[class='string required my_input']" assert_no_select "input[class='string required my_input ']" assert_no_select "input[class=' string required my_input']" end end simple-form-3.2.0/test/inputs/text_input_test.rb0000644000175000017500000000235312623141213022246 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class TextInputTest < ActionView::TestCase test 'input generates a text area for text attributes' do with_input_for @user, :description, :text assert_select 'textarea.text#user_description' end test 'input generates a text area for text attributes that accept placeholder' do with_input_for @user, :description, :text, placeholder: 'Put in some text' assert_select 'textarea.text[placeholder="Put in some text"]' end test 'input generates a placeholder from the translations' do store_translations(:en, simple_form: { placeholders: { user: { name: "placeholder from i18n en.simple_form.placeholders.user.name" } } }) do with_input_for @user, :name, :text assert_select 'textarea.text[placeholder="placeholder from i18n en.simple_form.placeholders.user.name"]' end end test 'input gets maxlength from column definition for text attributes' do with_input_for @user, :description, :text assert_select 'textarea.text[maxlength="200"]' end test 'input infers maxlength column definition from validation when present for text attributes' do with_input_for @validating_user, :description, :text assert_select 'textarea.text[maxlength="50"]' end end simple-form-3.2.0/test/inputs/disabled_test.rb0000644000175000017500000000556612623141213021623 0ustar terceiroterceirorequire 'test_helper' class DisabledTest < ActionView::TestCase test 'string input is disabled when disabled option is true' do with_input_for @user, :name, :string, disabled: true assert_select 'input.string.disabled[disabled]' end test 'text input is disabled when disabled option is true' do with_input_for @user, :description, :text, disabled: true assert_select 'textarea.text.disabled[disabled]' end test 'numeric input is disabled when disabled option is true' do with_input_for @user, :age, :integer, disabled: true assert_select 'input.integer.disabled[disabled]' end test 'date input is disabled when disabled option is true' do with_input_for @user, :born_at, :date, disabled: true assert_select 'select.date.disabled[disabled]' end test 'datetime input is disabled when disabled option is true' do with_input_for @user, :created_at, :datetime, disabled: true assert_select 'select.datetime.disabled[disabled]' end test 'string input does not be disabled when disabled option is false' do with_input_for @user, :name, :string, disabled: false assert_no_select 'input.string.disabled[disabled]' end test 'text input does not be disabled when disabled option is false' do with_input_for @user, :description, :text, disabled: false assert_no_select 'textarea.text.disabled[disabled]' end test 'numeric input does not be disabled when disabled option is false' do with_input_for @user, :age, :integer, disabled: false assert_no_select 'input.integer.disabled[disabled]' end test 'date input does not be disabled when disabled option is false' do with_input_for @user, :born_at, :date, disabled: false assert_no_select 'select.date.disabled[disabled]' end test 'datetime input does not be disabled when disabled option is false' do with_input_for @user, :created_at, :datetime, disabled: false assert_no_select 'select.datetime.disabled[disabled]' end test 'string input does not be disabled when disabled option is not present' do with_input_for @user, :name, :string assert_no_select 'input.string.disabled[disabled]' end test 'text input does not be disabled when disabled option is not present' do with_input_for @user, :description, :text assert_no_select 'textarea.text.disabled[disabled]' end test 'numeric input does not be disabled when disabled option is not present' do with_input_for @user, :age, :integer assert_no_select 'input.integer.disabled[disabled]' end test 'date input does not be disabled when disabled option is not present' do with_input_for @user, :born_at, :date assert_no_select 'select.date.disabled[disabled]' end test 'datetime input does not be disabled when disabled option is not present' do with_input_for @user, :created_at, :datetime assert_no_select 'select.datetime.disabled[disabled]' end end simple-form-3.2.0/test/support/0000755000175000017500000000000012623141213016646 5ustar terceiroterceirosimple-form-3.2.0/test/support/mock_controller.rb0000644000175000017500000000062512623141213022372 0ustar terceiroterceiroclass MockController attr_writer :action_name def _routes self end def action_name defined?(@action_name) ? @action_name : "edit" end def url_for(*args) "http://example.com" end def url_options {} end def hash_for_user_path(*); end def hash_for_validating_user_path(*); end def hash_for_other_validating_user_path(*); end def hash_for_users_path(*); end end simple-form-3.2.0/test/support/discovery_inputs.rb0000644000175000017500000000231712623141213022607 0ustar terceiroterceiroclass StringInput < SimpleForm::Inputs::StringInput def input(wrapper_options = nil) "
#{super}
".html_safe end end class NumericInput < SimpleForm::Inputs::NumericInput def input(wrapper_options = nil) "
#{super}
".html_safe end end class CustomizedInput < SimpleForm::Inputs::StringInput def input(wrapper_options = nil) "
#{super}
".html_safe end def input_method :text_field end end class DeprecatedInput < SimpleForm::Inputs::StringInput def input "
#{super}
".html_safe end def input_method :text_field end end class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput def input_html_classes super.push('chosen') end end module CustomInputs class CustomizedInput < SimpleForm::Inputs::StringInput def input_html_classes super.push('customized-namespace-custom-input') end end class PasswordInput < SimpleForm::Inputs::PasswordInput def input_html_classes super.push('password-custom-input') end end class NumericInput < SimpleForm::Inputs::PasswordInput def input_html_classes super.push('numeric-custom-input') end end end simple-form-3.2.0/test/support/misc_helpers.rb0000644000175000017500000001502112623141213021647 0ustar terceiroterceiromodule MiscHelpers def store_translations(locale, translations, &block) I18n.backend.store_translations locale, translations yield ensure I18n.reload! I18n.backend.send :init_translations end def assert_no_select(selector, value = nil) assert_select(selector, text: value, count: 0) end def swap(object, new_values) old_values = {} new_values.each do |key, value| old_values[key] = object.send key object.send :"#{key}=", value end yield ensure old_values.each do |key, value| object.send :"#{key}=", value end end def stub_any_instance(klass, method, value) klass.class_eval do alias_method :"new_#{method}", method define_method(method) do if value.respond_to?(:call) value.call else value end end end yield ensure klass.class_eval do undef_method method alias_method method, :"new_#{method}" undef_method :"new_#{method}" end end def swap_wrapper(name = :default, wrapper = custom_wrapper) old = SimpleForm.wrappers[name.to_s] SimpleForm.wrappers[name.to_s] = wrapper yield ensure SimpleForm.wrappers[name.to_s] = old end def custom_wrapper SimpleForm.build tag: :section, class: "custom_wrapper", pattern: false do |b| b.use :pattern b.wrapper :another, class: "another_wrapper" do |ba| ba.use :label ba.use :input end b.wrapper :error_wrapper, tag: :div, class: "error_wrapper" do |be| be.use :error, wrap_with: { tag: :span, class: "omg_error" } end b.use :hint, wrap_with: { class: "omg_hint" } end end def custom_wrapper_with_wrapped_optional_component SimpleForm.build tag: :section, class: "custom_wrapper" do |b| b.wrapper tag: :div, class: 'no_output_wrapper' do |ba| ba.optional :hint, wrap_with: { tag: :p, class: 'omg_hint' } end end end def custom_wrapper_with_unless_blank SimpleForm.build tag: :section, class: "custom_wrapper" do |b| b.wrapper tag: :div, class: 'no_output_wrapper', unless_blank: true do |ba| ba.optional :hint, wrap_with: { tag: :p, class: 'omg_hint' } end end end def custom_wrapper_with_input_class SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.use :label b.use :input, class: 'inline-class' end end def custom_wrapper_with_label_class SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.use :label, class: 'inline-class' b.use :input end end def custom_wrapper_with_input_attributes SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.use :input, data: { modal: true } end end def custom_wrapper_with_label_input_class SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.use :label_input, class: 'inline-class' end end def custom_wrapper_with_wrapped_input SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.wrapper tag: :div, class: 'elem' do |component| component.use :label component.use :input, wrap_with: { tag: :div, class: 'input' } end end end def custom_wrapper_with_wrapped_label SimpleForm.build tag: :div, class: "custom_wrapper" do |b| b.wrapper tag: :div, class: 'elem' do |component| component.use :label, wrap_with: { tag: :div, class: 'label' } component.use :input end end end def custom_wrapper_without_top_level SimpleForm.build tag: false, class: 'custom_wrapper_without_top_level' do |b| b.use :label_input b.use :hint, wrap_with: { tag: :span, class: :hint } b.use :error, wrap_with: { tag: :span, class: :error } end end def custom_wrapper_without_class SimpleForm.build tag: :div, wrapper_html: { id: 'custom_wrapper_without_class' } do |b| b.use :label_input end end def custom_wrapper_with_label_html_option SimpleForm.build tag: :div, class: "custom_wrapper", label_html: { class: 'extra-label-class' } do |b| b.use :label_input end end def custom_wrapper_with_wrapped_label_input SimpleForm.build tag: :section, class: "custom_wrapper", pattern: false do |b| b.use :label_input, wrap_with: { tag: :div, class: :field } end end def custom_wrapper_with_additional_attributes SimpleForm.build tag: :div, class: 'custom_wrapper', html: { data: { wrapper: :test }, title: 'some title' } do |b| b.use :label_input end end def custom_wrapper_with_full_error SimpleForm.build tag: :div, class: 'custom_wrapper' do |b| b.use :full_error, wrap_with: { tag: :span, class: :error } end end def custom_wrapper_with_label_text SimpleForm.build :label_text => proc { |label, required| "**#{label}**" } do |b| b.use :label_input end end def custom_wrapper_with_custom_label_component SimpleForm.build tag: :span, class: 'custom_wrapper' do |b| b.use :label_text end end def custom_wrapper_with_html5_components SimpleForm.build tag: :span, class: 'custom_wrapper' do |b| b.use :label_text end end def custom_wrapper_with_required_input SimpleForm.build tag: :span, class: 'custom_wrapper' do |b| b.use :html5 b.use :input, required: true end end def custom_form_for(object, *args, &block) simple_form_for(object, *args, { builder: CustomFormBuilder }, &block) end def custom_mapping_form_for(object, *args, &block) simple_form_for(object, *args, { builder: CustomMapTypeFormBuilder }, &block) end def with_concat_form_for(*args, &block) concat simple_form_for(*args, &(block || proc {})) end def with_concat_fields_for(*args, &block) concat simple_fields_for(*args, &block) end def with_concat_custom_form_for(*args, &block) concat custom_form_for(*args, &block) end def with_concat_custom_mapping_form_for(*args, &block) concat custom_mapping_form_for(*args, &block) end def with_form_for(object, *args, &block) with_concat_form_for(object) do |f| f.input(*args, &block) end end def with_input_for(object, attribute_name, type, options = {}) with_concat_form_for(object) do |f| f.input(attribute_name, options.merge(as: type)) end end end class CustomFormBuilder < SimpleForm::FormBuilder def input(attribute_name, *args, &block) super(attribute_name, *args, { input_html: { class: 'custom' } }, &block) end end class CustomMapTypeFormBuilder < SimpleForm::FormBuilder map_type :custom_type, to: SimpleForm::Inputs::StringInput end simple-form-3.2.0/test/support/models.rb0000644000175000017500000001602712623141213020464 0ustar terceiroterceiroAssociation = Struct.new(:klass, :name, :macro, :scope, :options) Column = Struct.new(:name, :type, :limit) do # Returns +true+ if the column is either of type integer, float or decimal. def number? type == :integer || type == :float || type == :decimal end end Relation = Struct.new(:records) do delegate :each, to: :records def where(conditions = nil) self.class.new conditions ? records.first : records end def order(conditions = nil) self.class.new conditions ? records.last : records end alias_method :to_a, :records alias_method :to_ary, :records end Picture = Struct.new(:id, :name) do extend ActiveModel::Naming include ActiveModel::Conversion def self.where(conditions = nil) if conditions.is_a?(Hash) && conditions[:name] all.to_a.last else all end end def self.all Relation.new((1..3).map { |i| new(i, "#{name} #{i}") }) end end Company = Struct.new(:id, :name) do extend ActiveModel::Naming include ActiveModel::Conversion class << self delegate :order, :where, to: :_relation end def self._relation all end def self.all Relation.new((1..3).map { |i| new(i, "#{name} #{i}") }) end def persisted? true end end class Tag < Company; end TagGroup = Struct.new(:id, :name, :tags) class User extend ActiveModel::Naming include ActiveModel::Conversion attr_accessor :id, :name, :company, :company_id, :time_zone, :active, :age, :description, :created_at, :updated_at, :credit_limit, :password, :url, :delivery_time, :born_at, :special_company_id, :country, :tags, :tag_ids, :avatar, :home_picture, :email, :status, :residence_country, :phone_number, :post_count, :lock_version, :amount, :attempts, :action, :credit_card, :gender, :extra_special_company_id, :pictures, :picture_ids, :special_pictures, :special_picture_ids, :uuid def self.build(extra_attributes = {}) attributes = { id: 1, name: 'New in SimpleForm!', description: 'Hello!', created_at: Time.now }.merge! extra_attributes new attributes end def initialize(options = {}) @new_record = false options.each do |key, value| send("#{key}=", value) end if options end def new_record! @new_record = true end def persisted? !@new_record end def company_attributes=(*) end def tags_attributes=(*) end def column_for_attribute(attribute) column_type, limit = case attribute.to_sym when :name, :status, :password then [:string, 100] when :description then [:text, 200] when :age then :integer when :credit_limit then [:decimal, 15] when :active then :boolean when :born_at then :date when :delivery_time then :time when :created_at then :datetime when :updated_at then :timestamp when :lock_version then :integer when :home_picture then :string when :amount then :integer when :attempts then :integer when :action then :string when :credit_card then :string when :uuid then :uuid end Column.new(attribute, column_type, limit) end def has_attribute?(attribute) case attribute.to_sym when :name, :status, :password, :description, :age, :credit_limit, :active, :born_at, :delivery_time, :created_at, :updated_at, :lock_version, :home_picture, :amount, :attempts, :action, :credit_card, :uuid then true else false end end def self.human_attribute_name(attribute, options = {}) case attribute when 'name' 'Super User Name!' when 'description' 'User Description!' when 'company' 'Company Human Name!' else attribute.to_s.humanize end end def self.reflect_on_association(association) case association when :company Association.new(Company, association, :belongs_to, nil, {}) when :tags Association.new(Tag, association, :has_many, nil, {}) when :first_company Association.new(Company, association, :has_one, nil, {}) when :special_company Association.new(Company, association, :belongs_to, nil, { conditions: { id: 1 } }) when :extra_special_company Association.new(Company, association, :belongs_to, nil, { conditions: proc { { id: self.id } } }) when :pictures Association.new(Picture, association, :has_many, nil, {}) when :special_pictures Association.new(Picture, association, :has_many, proc { where(name: self.name) }, {}) end end def errors @errors ||= begin errors = ActiveModel::Errors.new(self) errors.add(:name, "cannot be blank") errors.add(:description, 'must be longer than 15 characters') errors.add(:age, 'is not a number') errors.add(:age, 'must be greater than 18') errors.add(:company, 'company must be present') errors.add(:company_id, 'must be valid') errors end end def self.readonly_attributes ["credit_card"] end end class ValidatingUser < User include ActiveModel::Validations validates :name, presence: true validates :company, presence: true validates :age, presence: true, if: Proc.new { |user| user.name } validates :amount, presence: true, unless: Proc.new { |user| user.age } validates :action, presence: true, on: :create validates :credit_limit, presence: true, on: :save validates :phone_number, presence: true, on: :update validates_numericality_of :age, greater_than_or_equal_to: 18, less_than_or_equal_to: 99, only_integer: true validates_numericality_of :amount, greater_than: :min_amount, less_than: :max_amount, only_integer: true validates_numericality_of :attempts, greater_than_or_equal_to: :min_attempts, less_than_or_equal_to: :max_attempts, only_integer: true validates_length_of :name, maximum: 25 validates_length_of :description, maximum: 50 validates_length_of :action, maximum: 10, tokenizer: lambda { |str| str.scan(/\w+/) } validates_length_of :home_picture, is: 12 def min_amount 10 end def max_amount 100 end def min_attempts 1 end def max_attempts 100 end end class OtherValidatingUser < User include ActiveModel::Validations validates_numericality_of :age, greater_than: 17, less_than: 100, only_integer: true validates_numericality_of :amount, greater_than: Proc.new { |user| user.age }, less_than: Proc.new { |user| user.age + 100 }, only_integer: true validates_numericality_of :attempts, greater_than_or_equal_to: Proc.new { |user| user.age }, less_than_or_equal_to: Proc.new { |user| user.age + 100 }, only_integer: true validates_format_of :country, with: /\w+/ validates_format_of :name, with: Proc.new { /\w+/ } validates_format_of :description, without: /\d+/ end class HashBackedAuthor < Hash extend ActiveModel::Naming include ActiveModel::Conversion def persisted?; false; end def name 'hash backed author' end end class UserNumber1And2 < User end simple-form-3.2.0/test/generators/0000755000175000017500000000000012623141213017303 5ustar terceiroterceirosimple-form-3.2.0/test/generators/simple_form_generator_test.rb0000644000175000017500000000322512623141213025253 0ustar terceiroterceirorequire 'test_helper' class SimpleFormGeneratorTest < Rails::Generators::TestCase tests SimpleForm::Generators::InstallGenerator destination File.expand_path('../../tmp', __FILE__) setup :prepare_destination teardown { rm_rf(destination_root) } test 'generates example locale file' do run_generator assert_file 'config/locales/simple_form.en.yml' end test 'generates the simple_form initializer' do run_generator assert_file 'config/initializers/simple_form.rb', /config\.default_wrapper = :default/, /config\.boolean_style = :nested/ end test 'generates the simple_form initializer with the bootstrap wrappers' do run_generator %w(--bootstrap) assert_file 'config/initializers/simple_form.rb', /config\.default_wrapper = :default/, /config\.boolean_style = :nested/ assert_file 'config/initializers/simple_form_bootstrap.rb', /config\.wrappers :vertical_form/, /config\.wrappers :horizontal_form/, /config\.default_wrapper = :vertical_form/ end test 'generates the simple_form initializer with the foundation wrappers' do run_generator %w(--foundation) assert_file 'config/initializers/simple_form.rb', /config\.default_wrapper = :default/, /config\.boolean_style = :nested/ assert_file 'config/initializers/simple_form_foundation.rb', /config\.wrappers :vertical_form/, /config\.default_wrapper = :vertical_form/, /config\.item_wrapper_tag = :div/ end %W(erb haml slim).each do |engine| test "generates the scaffold template when using #{engine}" do run_generator ['-e', engine] assert_file "lib/templates/#{engine}/scaffold/_form.html.#{engine}" end end end simple-form-3.2.0/test/simple_form_test.rb0000644000175000017500000000056612623141213021041 0ustar terceiroterceirorequire 'test_helper' class SimpleFormTest < ActiveSupport::TestCase test 'setup block yields self' do SimpleForm.setup do |config| assert_equal SimpleForm, config end end test 'setup block configure Simple Form' do SimpleForm.setup do |config| assert_equal SimpleForm, config end assert_equal true, SimpleForm.configured? end end simple-form-3.2.0/test/form_builder/0000755000175000017500000000000012623141213017603 5ustar terceiroterceirosimple-form-3.2.0/test/form_builder/error_test.rb0000644000175000017500000001744212623141213022330 0ustar terceiroterceirorequire 'test_helper' # Tests for f.error and f.full_error class ErrorTest < ActionView::TestCase def with_error_for(object, *args) with_concat_form_for(object) do |f| f.error(*args) end end def with_full_error_for(object, *args) with_concat_form_for(object) do |f| f.full_error(*args) end end test 'error does not generate content for attribute without errors' do with_error_for @user, :active assert_no_select 'span.error' end test 'error does not generate messages when object is not present' do with_error_for :project, :name assert_no_select 'span.error' end test "error does not generate messages when object doesn't respond to errors method" do @user.instance_eval { undef errors } with_error_for @user, :name assert_no_select 'span.error' end test 'error generates messages for attribute with single error' do with_error_for @user, :name assert_select 'span.error', "cannot be blank" end test 'error generates messages for attribute with one error when using first' do swap SimpleForm, error_method: :first do with_error_for @user, :age assert_select 'span.error', 'is not a number' end end test 'error generates messages for attribute with several errors when using to_sentence' do swap SimpleForm, error_method: :to_sentence do with_error_for @user, :age assert_select 'span.error', 'is not a number and must be greater than 18' end end test 'error is able to pass html options' do with_error_for @user, :name, id: 'error', class: 'yay' assert_select 'span#error.error.yay' end test 'error does not modify the options hash' do options = { id: 'error', class: 'yay' } with_error_for @user, :name, options assert_select 'span#error.error.yay' assert_equal({ id: 'error', class: 'yay' }, options) end test 'error finds errors on attribute and association' do with_error_for @user, :company_id, as: :select, error_method: :to_sentence, reflection: Association.new(Company, :company, {}) assert_select 'span.error', 'must be valid and company must be present' end test 'error generates an error tag with a clean HTML' do with_error_for @user, :name assert_no_select 'span.error[error_html]' end test 'error generates an error tag with a clean HTML when errors options are present' do with_error_for @user, :name, error_tag: :p, error_prefix: 'Name', error_method: :first assert_no_select 'p.error[error_html]' assert_no_select 'p.error[error_tag]' assert_no_select 'p.error[error_prefix]' assert_no_select 'p.error[error_method]' end test 'error escapes error prefix text' do with_error_for @user, :name, error_prefix: 'Name' assert_no_select 'span.error b' end test 'error escapes error text' do @user.errors.add(:action, 'must not contain markup') with_error_for @user, :action assert_select 'span.error' assert_no_select 'span.error b', 'markup' end test 'error generates an error message with raw HTML tags' do with_error_for @user, :name, error_prefix: 'Name'.html_safe assert_select 'span.error', "Name cannot be blank" assert_select 'span.error b', "Name" end # FULL ERRORS test 'full error generates a full error tag for the attribute' do with_full_error_for @user, :name assert_select 'span.error', "Super User Name! cannot be blank" end test 'full error generates a full error tag with a clean HTML' do with_full_error_for @user, :name assert_no_select 'span.error[error_html]' end test 'full error allows passing options to full error tag' do with_full_error_for @user, :name, id: 'name_error', error_prefix: "Your name" assert_select 'span.error#name_error', "Your name cannot be blank" end test 'full error does not modify the options hash' do options = { id: 'name_error' } with_full_error_for @user, :name, options assert_select 'span.error#name_error', "Super User Name! cannot be blank" assert_equal({ id: 'name_error' }, options) end test 'full error escapes error text' do @user.errors.add(:action, 'must not contain markup') with_full_error_for @user, :action assert_select 'span.error' assert_no_select 'span.error b', 'markup' end # CUSTOM WRAPPERS test 'error with custom wrappers works' do swap_wrapper do with_error_for @user, :name assert_select 'span.omg_error', "cannot be blank" end end # FULL_ERROR_WRAPPER test 'full error finds errors on association' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :company_id, as: :select assert_select 'span.error', 'Company must be valid' end end test 'full error finds errors on association with reflection' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :company_id, as: :select, reflection: Association.new(Company, :company, {}) assert_select 'span.error', 'Company must be valid' end end test 'full error can be disabled' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :company_id, as: :select, full_error: false assert_no_select 'span.error' end end test 'full error can be disabled setting error to false' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :company_id, as: :select, error: false assert_no_select 'span.error' end end # CUSTOM ERRORS test 'input with custom error works' do error_text = "Super User Name! cannot be blank" with_form_for @user, :name, error: error_text assert_select 'span.error', error_text end test 'input with error option as true does not use custom error' do with_form_for @user, :name, error: true assert_select 'span.error', "cannot be blank" end test 'input with custom error does not generate the error if there is no error on the attribute' do with_form_for @user, :active, error: "Super User Active! cannot be blank" assert_no_select 'span.error' end test 'input with custom error works when using full_error component' do swap_wrapper :default, custom_wrapper_with_full_error do error_text = "Super User Name! cannot be blank" with_form_for @user, :name, error: error_text assert_select 'span.error', error_text end end test 'input with custom error escapes the error text' do with_form_for @user, :name, error: 'error must not contain markup' assert_select 'span.error' assert_no_select 'span.error b', 'markup' end test 'input with custom error does not escape the error text if it is safe' do with_form_for @user, :name, error: 'error must contain markup'.html_safe assert_select 'span.error' assert_select 'span.error b', 'markup' end test 'input with custom error escapes the error text using full_error component' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :name, error: 'error must not contain markup' assert_select 'span.error' assert_no_select 'span.error b', 'markup' end end test 'input with custom error does not escape the error text if it is safe using full_error component' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :name, error: 'error must contain markup'.html_safe assert_select 'span.error' assert_select 'span.error b', 'markup' end end test 'input with custom error when using full_error component does not generate the error if there is no error on the attribute' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :active, error: "Super User Active! can't be blank" assert_no_select 'span.error' end end end simple-form-3.2.0/test/form_builder/label_test.rb0000644000175000017500000001047212623141213022252 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class LabelTest < ActionView::TestCase def with_label_for(object, *args, &block) with_concat_form_for(object) do |f| f.label(*args, &block) end end test 'builder generates a label for the attribute' do with_label_for @user, :name assert_select 'label.string[for=user_name]', /Name/ end test 'builder generates a label for the boolean attrbiute' do with_label_for @user, :name, as: :boolean assert_select 'label.boolean[for=user_name]', /Name/ assert_no_select 'label[as=boolean]' end test 'builder generates a label component tag with a clean HTML' do with_label_for @user, :name assert_no_select 'label.string[label_html]' end test 'builder adds a required class to label if the attribute is required' do with_label_for @validating_user, :name assert_select 'label.string.required[for=validating_user_name]', /Name/ end test 'builder adds a disabled class to label if the attribute is disabled' do with_label_for @validating_user, :name, disabled: true assert_select 'label.string.disabled[for=validating_user_name]', /Name/ end test 'builder does not add a disabled class to label if the attribute is not disabled' do with_label_for @validating_user, :name, disabled: false assert_no_select 'label.string.disabled[for=validating_user_name]', /Name/ end test 'builder escapes label text' do with_label_for @user, :name, label: '', required: false assert_no_select 'label.string script' end test 'builder does not escape label text if it is safe' do with_label_for @user, :name, label: ''.html_safe, required: false assert_select 'label.string script', "alert(1337)" end test 'builder allows passing options to label tag' do with_label_for @user, :name, label: 'My label', id: 'name_label' assert_select 'label.string#name_label', /My label/ end test 'builder label generates label tag with clean HTML' do with_label_for @user, :name, label: 'My label', required: true, id: 'name_label' assert_select 'label.string#name_label', /My label/ assert_no_select 'label[label]' assert_no_select 'label[required]' end test 'builder does not modify the options hash' do options = { label: 'My label', id: 'name_label' } with_label_for @user, :name, options assert_select 'label.string#name_label', /My label/ assert_equal({ label: 'My label', id: 'name_label' }, options) end test 'builder fallbacks to default label when string is given' do with_label_for @user, :name, 'Nome do usuário' assert_select 'label', 'Nome do usuário' assert_no_select 'label.string' end test 'builder fallbacks to default label when block is given' do with_label_for @user, :name do 'Nome do usuário' end assert_select 'label', 'Nome do usuário' assert_no_select 'label.string' end test 'builder allows label order to be changed' do swap SimpleForm, label_text: proc { |l, r| "#{l}:" } do with_label_for @user, :age assert_select 'label.integer[for=user_age]', "Age:" end end test 'configuration allow set label text for wrappers' do swap_wrapper :default, custom_wrapper_with_label_text do with_concat_form_for(@user) do |f| concat f.input :age end assert_select "label.integer[for=user_age]", "**Age**" end end test 'configuration allow set rewrited label tag for wrappers' do swap_wrapper :default, custom_wrapper_with_custom_label_component do with_concat_form_for(@user) do |f| concat f.input :age end assert_select "span.integer.user_age", /Age/ end end test 'builder allows custom formatting when label is explicitly specified' do swap SimpleForm, label_text: lambda { |l, r, explicit_label| explicit_label ? l : "#{l.titleize}:" } do with_label_for @user, :time_zone, 'What is your home time zone?' assert_select 'label[for=user_time_zone]', 'What is your home time zone?' end end test 'builder allows custom formatting when label is generated' do swap SimpleForm, label_text: lambda { |l, r, explicit_label| explicit_label ? l : "#{l.titleize}:" } do with_label_for @user, :time_zone assert_select 'label[for=user_time_zone]', 'Time Zone:' end end end simple-form-3.2.0/test/form_builder/hint_test.rb0000644000175000017500000001076612623141213022143 0ustar terceiroterceirorequire 'test_helper' # Tests for f.hint class HintTest < ActionView::TestCase def with_hint_for(object, *args) with_concat_form_for(object) do |f| f.hint(*args) end end test 'hint does not be generated by default' do with_hint_for @user, :name assert_no_select 'span.hint' end test 'hint is generated with optional text' do with_hint_for @user, :name, hint: 'Use with care...' assert_select 'span.hint', 'Use with care...' end test 'hint does not modify the options hash' do options = { hint: 'Use with care...' } with_hint_for @user, :name, options assert_select 'span.hint', 'Use with care...' assert_equal({ hint: 'Use with care...' }, options) end test 'hint is generated cleanly with optional text' do with_hint_for @user, :name, hint: 'Use with care...', hint_tag: :span assert_no_select 'span.hint[hint]' assert_no_select 'span.hint[hint_tag]' assert_no_select 'span.hint[hint_html]' end test 'hint uses the current component tag set' do with_hint_for @user, :name, hint: 'Use with care...', hint_tag: :p assert_select 'p.hint', 'Use with care...' end test 'hint is able to pass html options' do with_hint_for @user, :name, hint: 'Yay!', id: 'hint', class: 'yay' assert_select 'span#hint.hint.yay' end test 'hint is output as html_safe' do with_hint_for @user, :name, hint: 'Bold and not...'.html_safe assert_select 'span.hint', 'Bold and not...' assert_select 'span.hint b', 'Bold' end test 'builder escapes hint text' do with_hint_for @user, :name, hint: '' assert_no_select 'span.hint script' end # Without attribute name test 'hint without attribute name' do with_hint_for @validating_user, 'Hello World!' assert_select 'span.hint', 'Hello World!' end test 'hint without attribute name generates component tag with a clean HTML' do with_hint_for @validating_user, 'Hello World!' assert_no_select 'span.hint[hint]' assert_no_select 'span.hint[hint_html]' end test 'hint without attribute name uses the current component tag set' do with_hint_for @user, 'Hello World!', hint_tag: :p assert_no_select 'p.hint[hint]' assert_no_select 'p.hint[hint_html]' assert_no_select 'p.hint[hint_tag]' end test 'hint without attribute name is able to pass html options' do with_hint_for @user, 'Yay', id: 'hint', class: 'yay' assert_select 'span#hint.hint.yay', 'Yay' end # I18n test 'hint uses i18n based on model, action, and attribute to lookup translation' do store_translations(:en, simple_form: { hints: { user: { edit: { name: 'Content of this input will be truncated...' } } } }) do with_hint_for @user, :name assert_select 'span.hint', 'Content of this input will be truncated...' end end test 'hint uses i18n with model and attribute to lookup translation' do store_translations(:en, simple_form: { hints: { user: { name: 'Content of this input will be capitalized...' } } }) do with_hint_for @user, :name assert_select 'span.hint', 'Content of this input will be capitalized...' end end test 'hint uses i18n under defaults namespace to lookup translation' do store_translations(:en, simple_form: { hints: { defaults: { name: 'Content of this input will be downcased...' } } }) do with_hint_for @user, :name assert_select 'span.hint', 'Content of this input will be downcased...' end end test 'hint uses i18n with lookup for association name' do store_translations(:en, simple_form: { hints: { user: { company: 'My company!' } } } ) do with_hint_for @user, :company_id, as: :string, reflection: Association.new(Company, :company, {}) assert_select 'span.hint', /My company!/ end end test 'hint outputs translations as html_safe' do store_translations(:en, simple_form: { hints: { user: { edit: { name: 'This is bold and this is not...' } } } }) do with_hint_for @user, :name assert_select 'span.hint', 'This is bold and this is not...' end end # No object test 'hint generates properly when object is not present' do with_hint_for :project, :name, hint: 'Test without object' assert_select 'span.hint', 'Test without object' end # Custom wrappers test 'hint with custom wrappers works' do swap_wrapper do with_hint_for @user, :name, hint: "cannot be blank" assert_select 'div.omg_hint', "cannot be blank" end end end simple-form-3.2.0/test/form_builder/error_notification_test.rb0000644000175000017500000000575512623141213025102 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' # Tests for f.error_notification class ErrorNotificationTest < ActionView::TestCase def with_error_notification_for(object, options = {}, &block) with_concat_form_for(object) do |f| f.error_notification(options) end end test 'error notification is not generated when the object has no error' do assert @validating_user.valid? with_error_notification_for @validating_user assert_no_select 'p.error_notification' end test 'error notification is not generated for forms without objects' do with_error_notification_for :user assert_no_select 'p.error_notification' end test 'error notification is generated when the object has some error' do with_error_notification_for @user assert_select 'p.error_notification', 'Please review the problems below:' end test 'error notification uses I18n based on model to generate the notification message' do store_translations(:en, simple_form: { error_notification: { user: 'Alguns erros foram encontrados para o usuário:' } }) do with_error_notification_for @user assert_select 'p.error_notification', 'Alguns erros foram encontrados para o usuário:' end end test 'error notification uses I18n fallbacking to default message' do store_translations(:en, simple_form: { error_notification: { default_message: 'Opa! Alguns erros foram encontrados, poderia verificar?' } }) do with_error_notification_for @user assert_select 'p.error_notification', 'Opa! Alguns erros foram encontrados, poderia verificar?' end end test 'error notification allows passing the notification message' do with_error_notification_for @user, message: 'Erro encontrado ao criar usuario' assert_select 'p.error_notification', 'Erro encontrado ao criar usuario' end test 'error notification accepts other html options' do with_error_notification_for @user, id: 'user_error_message', class: 'form_error' assert_select 'p#user_error_message.form_error.error_notification' end test 'error notification allows configuring the wrapper element' do swap SimpleForm, error_notification_tag: :div do with_error_notification_for @user assert_select 'div.error_notification' end end test 'error notification can contain HTML tags' do with_error_notification_for @user, message: 'Erro encontrado ao criar usuário' assert_select 'p.error_notification', 'Erro encontrado ao criar usuário' assert_select 'p.error_notification b', 'usuário' end test 'error notification uses I18n based on model to generate the notification message and accepts HTML' do store_translations(:en, simple_form: { error_notification: { user: 'Alguns erros foram encontrados para o usuário:' } }) do with_error_notification_for @user assert_select 'p.error_notification', 'Alguns erros foram encontrados para o usuário:' assert_select 'p.error_notification b', 'usuário' end end end simple-form-3.2.0/test/form_builder/button_test.rb0000644000175000017500000000270112623141213022502 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class ButtonTest < ActionView::TestCase def with_button_for(object, *args) with_concat_form_for(object) do |f| f.button(*args) end end test 'builder creates buttons' do with_button_for :post, :submit assert_select 'form input.button[type=submit][value="Save Post"]' end test 'builder creates buttons with options' do with_button_for :post, :submit, class: 'my_button' assert_select 'form input.button.my_button[type=submit][value="Save Post"]' end test 'builder does not modify the options hash' do options = { class: 'my_button' } with_button_for :post, :submit, options assert_select 'form input.button.my_button[type=submit][value="Save Post"]' assert_equal({ class: 'my_button' }, options) end test 'builder creates buttons for records' do @user.new_record! with_button_for @user, :submit assert_select 'form input.button[type=submit][value="Create User"]' end test "builder uses the default class from the configuration" do swap SimpleForm, button_class: 'btn' do with_button_for :post, :submit assert_select 'form input.btn[type=submit][value="Save Post"]' end end if ActionView::Helpers::FormBuilder.method_defined?(:button) test "allows to use Rails button helper when available" do with_button_for :post, :button, 'Save!' assert_select 'form button.button[type=submit]', 'Save!' end end end simple-form-3.2.0/test/form_builder/input_field_test.rb0000644000175000017500000001153712623141213023500 0ustar terceiroterceirorequire 'test_helper' # Tests for f.input_field class InputFieldTest < ActionView::TestCase def with_input_field_for(object, *args) with_concat_form_for(object) do |f| f.input_field(*args) end end test "builder input_field only renders the input tag, nothing else" do with_input_field_for @user, :name assert_select 'form > input.required.string' assert_no_select 'div.string' assert_no_select 'label' assert_no_select '.hint' end test 'builder input_field allows overriding default input type' do with_input_field_for @user, :name, as: :text assert_no_select 'input#user_name' assert_select 'textarea#user_name.text' end test 'builder input_field generates input type based on column type' do with_input_field_for @user, :age assert_select 'input[type=number].integer#user_age' end test 'builder input_field is able to disable any component' do with_input_field_for @user, :age, html5: false assert_no_select 'input[html5=false]#user_age' assert_select 'input[type=text].integer#user_age' end test 'builder input_field allows passing options to input tag' do with_input_field_for @user, :name, id: 'name_input', class: 'name' assert_select 'input.string.name#name_input' end test 'builder input_field does not modify the options hash' do options = { id: 'name_input', class: 'name' } with_input_field_for @user, :name, options assert_select 'input.string.name#name_input' assert_equal({ id: 'name_input', class: 'name' }, options) end test 'builder input_field generates an input tag with a clean HTML' do with_input_field_for @user, :name, as: :integer, class: 'name' assert_no_select 'input.integer[input_html]' assert_no_select 'input.integer[as]' end test 'builder input_field uses i18n to translate placeholder text' do store_translations(:en, simple_form: { placeholders: { user: { name: 'Name goes here' } } }) do with_input_field_for @user, :name assert_select 'input.string[placeholder="Name goes here"]' end end test 'builder input_field uses min_max component' do with_input_field_for @other_validating_user, :age, as: :integer assert_select 'input[min="18"]' end test 'builder input_field does not use pattern component by default' do with_input_field_for @other_validating_user, :country, as: :string assert_no_select 'input[pattern="\w+"]' end test 'builder input_field infers pattern from attributes' do with_input_field_for @other_validating_user, :country, as: :string, pattern: true assert_select 'input[pattern="\w+"]' end test 'builder input_field accepts custom patter' do with_input_field_for @other_validating_user, :country, as: :string, pattern: '\d+' assert_select 'input[pattern="\d+"]' end test 'builder input_field uses readonly component' do with_input_field_for @other_validating_user, :age, as: :integer, readonly: true assert_select 'input.integer.readonly[readonly]' end test 'builder input_field uses maxlength component' do with_input_field_for @validating_user, :name, as: :string assert_select 'input.string[maxlength="25"]' end test 'builder collection input_field generates input tag with a clean HTML' do with_input_field_for @user, :status, collection: ['Open', 'Closed'], class: 'status', label_method: :to_s, value_method: :to_s assert_no_select 'select.status[input_html]' assert_no_select 'select.status[collection]' assert_no_select 'select.status[label_method]' assert_no_select 'select.status[value_method]' end test 'build input_field does not treat "boolean_style" as a HTML attribute' do with_input_field_for @user, :active, boolean_style: :nested assert_no_select 'input.boolean[boolean_style]' end test 'build input_field without pattern component use the pattern string' do swap_wrapper :default, custom_wrapper_with_html5_components do with_input_field_for @user, :name, pattern: '\w+' assert_select 'input[pattern="\w+"]' end end test 'build input_field without placeholder component use the placeholder string' do swap_wrapper :default, custom_wrapper_with_html5_components do with_input_field_for @user, :name, placeholder: 'Placeholder' assert_select 'input[placeholder="Placeholder"]' end end test 'build input_field without maxlength component use the maxlength string' do swap_wrapper :default, custom_wrapper_with_html5_components do with_input_field_for @user, :name, maxlength: 5 assert_select 'input[maxlength="5"]' end end test 'build input_field without readonly component use the readonly string' do swap_wrapper :default, custom_wrapper_with_html5_components do with_input_field_for @user, :name, readonly: true assert_select 'input[readonly="readonly"]' end end end simple-form-3.2.0/test/form_builder/wrapper_test.rb0000644000175000017500000002521412623141213022653 0ustar terceiroterceirorequire 'test_helper' class WrapperTest < ActionView::TestCase test 'wrapper does not have error class for attribute without errors' do with_form_for @user, :active assert_no_select 'div.field_with_errors' end test 'wrapper does not have error class when object is not present' do with_form_for :project, :name assert_no_select 'div.field_with_errors' end test 'wrapper adds the attribute name class' do with_form_for @user, :name assert_select 'div.user_name' end test 'wrapper adds the attribute name class for nested forms' do @user.company = Company.new(1, 'Empresa') with_concat_form_for @user do |f| concat(f.simple_fields_for(:company) do |company_form| concat(company_form.input :name) end) end assert_select 'div.user_company_name' end test 'wrapper adds the association name class' do with_form_for @user, :company assert_select 'div.user_company' end test 'wrapper adds error class for attribute with errors' do with_form_for @user, :name assert_select 'div.field_with_errors' end test 'wrapper adds hint class for attribute with a hint' do with_form_for @user, :name, hint: 'hint' assert_select 'div.field_with_hint' end test 'wrapper does not have disabled class by default' do with_form_for @user, :active assert_no_select 'div.disabled' end test 'wrapper has disabled class when input is disabled' do with_form_for @user, :active, disabled: true assert_select 'div.disabled' end test 'wrapper supports no wrapping when wrapper is false' do with_form_for @user, :name, wrapper: false assert_select 'form > label[for=user_name]' assert_select 'form > input#user_name.string' end test 'wrapper supports no wrapping when wrapper tag is false' do with_form_for @user, :name, wrapper: custom_wrapper_without_top_level assert_select 'form > label[for=user_name]' assert_select 'form > input#user_name.string' end test 'wrapper wraps tag adds required/optional css classes' do with_form_for @user, :name assert_select 'form div.input.required.string' with_form_for @user, :age, required: false assert_select 'form div.input.optional.integer' end test 'wrapper allows custom options to be given' do with_form_for @user, :name, wrapper_html: { id: "super_cool", class: 'yay' } assert_select 'form #super_cool.required.string.yay' end test 'wrapper allows tag to be given on demand' do with_form_for @user, :name, wrapper_tag: :b assert_select 'form b.required.string' end test 'wrapper allows wrapper class to be given on demand' do with_form_for @user, :name, wrapper_class: :wrapper assert_select 'form div.wrapper.required.string' end test 'wrapper skips additional classes when configured' do swap SimpleForm, generate_additional_classes_for: [:input, :label] do with_form_for @user, :name, wrapper_class: :wrapper assert_select 'form div.wrapper' assert_no_select 'div.required' assert_no_select 'div.string' assert_no_select 'div.user_name' end end test 'wrapper does not generate empty css class' do swap SimpleForm, generate_additional_classes_for: [:input, :label] do swap_wrapper :default, custom_wrapper_without_class do with_form_for @user, :name assert_no_select 'div#custom_wrapper_without_class[class]' end end end # Custom wrapper test test 'custom wrappers works' do swap_wrapper do with_form_for @user, :name, hint: "cool" assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" assert_no_select "section.custom_wrapper div.another_wrapper span.omg_error" assert_select "section.custom_wrapper div.error_wrapper span.omg_error" assert_select "section.custom_wrapper > div.omg_hint", "cool" end end test 'custom wrappers can be turned off' do swap_wrapper do with_form_for @user, :name, another: false assert_no_select "section.custom_wrapper div.another_wrapper label" assert_no_select "section.custom_wrapper div.another_wrapper input.string" assert_select "section.custom_wrapper div.error_wrapper span.omg_error" end end test 'custom wrappers can have additional attributes' do swap_wrapper :default, custom_wrapper_with_additional_attributes do with_form_for @user, :name assert_select "div.custom_wrapper[title='some title'][data-wrapper='test']" end end test 'custom wrappers can have full error message on attributes' do swap_wrapper :default, custom_wrapper_with_full_error do with_form_for @user, :name assert_select 'span.error', "Name cannot be blank" end end test 'custom wrappers on a form basis' do swap_wrapper :another do with_concat_form_for(@user) do |f| f.input :name end assert_no_select "section.custom_wrapper div.another_wrapper label" assert_no_select "section.custom_wrapper div.another_wrapper input.string" with_concat_form_for(@user, wrapper: :another) do |f| f.input :name end assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end end test 'custom wrappers on input basis' do swap_wrapper :another do with_form_for @user, :name assert_no_select "section.custom_wrapper div.another_wrapper label" assert_no_select "section.custom_wrapper div.another_wrapper input.string" output_buffer.replace "" with_form_for @user, :name, wrapper: :another assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" output_buffer.replace "" end with_form_for @user, :name, wrapper: custom_wrapper assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end test 'access wrappers with indifferent access' do swap_wrapper :another do with_form_for @user, :name, wrapper: "another" assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end end test 'does not duplicate label classes for different inputs' do swap_wrapper :default, custom_wrapper_with_label_html_option do with_concat_form_for(@user) do |f| concat f.input :name, required: false concat f.input :email, as: :email, required: true end assert_select "label.string.optional.extra-label-class[for='user_name']" assert_select "label.email.required.extra-label-class[for='user_email']" assert_no_select "label.string.optional.extra-label-class[for='user_email']" end end test 'raise error when wrapper not found' do assert_raise SimpleForm::WrapperNotFound do with_form_for @user, :name, wrapper: :not_found end end test 'uses wrapper for specified in config mapping' do swap_wrapper :another do swap SimpleForm, wrapper_mappings: { string: :another } do with_form_for @user, :name assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end end end test 'uses custom wrapper mapping per form basis' do swap_wrapper :another do with_concat_form_for @user, wrapper_mappings: { string: :another } do |f| concat f.input :name end end assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end test 'simple_fields_form reuses custom wrapper mapping per form basis' do @user.company = Company.new(1, 'Empresa') swap_wrapper :another do with_concat_form_for @user, wrapper_mappings: { string: :another } do |f| concat(f.simple_fields_for(:company) do |company_form| concat(company_form.input(:name)) end) end end assert_select "section.custom_wrapper div.another_wrapper label" assert_select "section.custom_wrapper div.another_wrapper input.string" end test 'input accepts attributes in the DSL' do swap_wrapper :default, custom_wrapper_with_input_class do with_concat_form_for @user do |f| concat f.input :name end end assert_select "div.custom_wrapper input.string.inline-class" end test 'label accepts attributes in the DSL' do swap_wrapper :default, custom_wrapper_with_label_class do with_concat_form_for @user do |f| concat f.input :name end end assert_select "div.custom_wrapper label.string.inline-class" end test 'label_input accepts attributes in the DSL' do swap_wrapper :default, custom_wrapper_with_label_input_class do with_concat_form_for @user do |f| concat f.input :name end end assert_select "div.custom_wrapper label.string.inline-class" assert_select "div.custom_wrapper input.string.inline-class" end test 'input accepts data attributes in the DSL' do swap_wrapper :default, custom_wrapper_with_input_attributes do with_concat_form_for @user do |f| concat f.input :name end end assert_select "div.custom_wrapper input.string[data-modal=true]" end test 'inline wrapper displays when there is content' do swap_wrapper :default, custom_wrapper_with_wrapped_optional_component do with_form_for @user, :name, hint: "cannot be blank" assert_select 'section.custom_wrapper div.no_output_wrapper p.omg_hint', "cannot be blank" assert_select 'p.omg_hint' end end test 'inline wrapper does not display when there is no content' do swap_wrapper :default, custom_wrapper_with_wrapped_optional_component do with_form_for @user, :name assert_select 'section.custom_wrapper div.no_output_wrapper' assert_no_select 'p.omg_hint' end end test 'optional wrapper does not display when there is content' do swap_wrapper :default, custom_wrapper_with_unless_blank do with_form_for @user, :name, hint: "can't be blank" assert_select 'section.custom_wrapper div.no_output_wrapper' assert_select 'div.no_output_wrapper' assert_select 'p.omg_hint' end end test 'optional wrapper does not display when there is no content' do swap_wrapper :default, custom_wrapper_with_unless_blank do with_form_for @user, :name assert_no_select 'section.custom_wrapper div.no_output_wrapper' assert_no_select 'div.no_output_wrapper' assert_no_select 'p.omg_hint' end end end simple-form-3.2.0/test/form_builder/association_test.rb0000644000175000017500000002045312623141213023507 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class AssociationTest < ActionView::TestCase def with_association_for(object, *args) with_concat_form_for(object) do |f| f.association(*args) end end test 'builder does not allow creating an association input when no object exists' do assert_raise ArgumentError do with_association_for :post, :author end end test 'builder association with a block calls simple_fields_for' do simple_form_for @user do |f| f.association :posts do |posts_form| assert posts_form.instance_of?(SimpleForm::FormBuilder) end end end test 'builder association forwards collection to simple_fields_for' do calls = 0 simple_form_for @user do |f| f.association :company, collection: Company.all do |c| calls += 1 end end assert_equal 3, calls end test 'builder association marks input as required based on both association and attribute' do swap SimpleForm, required_by_default: false do with_association_for @validating_user, :company, collection: [] assert_select 'label.required' end end test 'builder preloads collection association' do value = @user.tags = MiniTest::Mock.new value.expect(:to_a, value) with_association_for @user, :tags assert_select 'form select.select#user_tag_ids' assert_select 'form select option[value="1"]', 'Tag 1' assert_select 'form select option[value="2"]', 'Tag 2' assert_select 'form select option[value="3"]', 'Tag 3' value.verify end test 'builder does not preload collection association if preload is false' do value = @user.tags = MiniTest::Mock.new value.expect(:to_a, nil) with_association_for @user, :tags, preload: false assert_select 'form select.select#user_tag_ids' assert_select 'form select option[value="1"]', 'Tag 1' assert_select 'form select option[value="2"]', 'Tag 2' assert_select 'form select option[value="3"]', 'Tag 3' assert_raises MockExpectationError do value.verify end end test 'builder does not preload non-collection association' do value = @user.company = MiniTest::Mock.new value.expect(:to_a, nil) with_association_for @user, :company assert_select 'form select.select#user_company_id' assert_select 'form select option[value="1"]', 'Company 1' assert_select 'form select option[value="2"]', 'Company 2' assert_select 'form select option[value="3"]', 'Company 3' assert_raises MockExpectationError do value.verify end end # ASSOCIATIONS - BELONGS TO test 'builder creates a select for belongs_to associations' do with_association_for @user, :company assert_select 'form select.select#user_company_id' assert_select 'form select option[value="1"]', 'Company 1' assert_select 'form select option[value="2"]', 'Company 2' assert_select 'form select option[value="3"]', 'Company 3' end test 'builder creates blank select if collection is nil' do with_association_for @user, :company, collection: nil assert_select 'form select.select#user_company_id' assert_no_select 'form select option[value="1"]', 'Company 1' end test 'builder allows collection radio for belongs_to associations' do with_association_for @user, :company, as: :radio_buttons assert_select 'form input.radio_buttons#user_company_id_1' assert_select 'form input.radio_buttons#user_company_id_2' assert_select 'form input.radio_buttons#user_company_id_3' end test 'builder allows collection to have a proc as a condition' do with_association_for @user, :extra_special_company assert_select 'form select.select#user_extra_special_company_id' assert_select 'form select option[value="1"]' assert_no_select 'form select option[value="2"]' assert_no_select 'form select option[value="3"]' end test 'builder allows collection to have a scope' do with_association_for @user, :special_pictures assert_select 'form select.select#user_special_picture_ids' assert_select 'form select option[value="3"]', '3' assert_no_select 'form select option[value="1"]' assert_no_select 'form select option[value="2"]' end test 'builder marks the record which already belongs to the user' do @user.company_id = 2 with_association_for @user, :company, as: :radio_buttons assert_no_select 'form input.radio_buttons#user_company_id_1[checked=checked]' assert_select 'form input.radio_buttons#user_company_id_2[checked=checked]' assert_no_select 'form input.radio_buttons#user_company_id_3[checked=checked]' end # ASSOCIATIONS - FINDERS test 'builder uses reflection conditions to find collection' do with_association_for @user, :special_company assert_select 'form select.select#user_special_company_id' assert_select 'form select option[value="1"]' assert_no_select 'form select option[value="2"]' assert_no_select 'form select option[value="3"]' end test 'builder allows overriding collection to association input' do with_association_for @user, :company, include_blank: false, collection: [Company.new(999, 'Teste')] assert_select 'form select.select#user_company_id' assert_no_select 'form select option[value="1"]' assert_select 'form select option[value="999"]', 'Teste' assert_select 'form select option', count: 1 end # ASSOCIATIONS - has_* test 'builder does not allow has_one associations' do assert_raise ArgumentError do with_association_for @user, :first_company, as: :radio_buttons end end test 'builder does not call order if the given association does not respond to it' do with_association_for @user, :pictures assert_select 'form select.select#user_picture_ids' assert_select 'form select[multiple=multiple]' assert_select 'form select option[value="1"]', 'Picture 1' assert_select 'form select option[value="2"]', 'Picture 2' assert_select 'form select option[value="3"]', 'Picture 3' end test 'builder creates a select with multiple options for collection associations' do with_association_for @user, :tags assert_select 'form select.select#user_tag_ids' assert_select 'form select[multiple=multiple]' assert_select 'form select option[value="1"]', 'Tag 1' assert_select 'form select option[value="2"]', 'Tag 2' assert_select 'form select option[value="3"]', 'Tag 3' end test 'builder allows size to be overwritten for collection associations' do with_association_for @user, :tags, input_html: { size: 10 } assert_select 'form select[multiple=multiple][size="10"]' end test 'builder marks all selected records which already belongs to user' do @user.tag_ids = [1, 2] with_association_for @user, :tags assert_select 'form select option[value="1"][selected=selected]' assert_select 'form select option[value="2"][selected=selected]' assert_no_select 'form select option[value="3"][selected=selected]' end test 'builder allows a collection of check boxes for collection associations' do @user.tag_ids = [1, 2] with_association_for @user, :tags, as: :check_boxes assert_select 'form input#user_tag_ids_1[type=checkbox]' assert_select 'form input#user_tag_ids_2[type=checkbox]' assert_select 'form input#user_tag_ids_3[type=checkbox]' end test 'builder marks all selected records for collection boxes' do @user.tag_ids = [1, 2] with_association_for @user, :tags, as: :check_boxes assert_select 'form input[type=checkbox][value="1"][checked=checked]' assert_select 'form input[type=checkbox][value="2"][checked=checked]' assert_no_select 'form input[type=checkbox][value="3"][checked=checked]' end test 'builder with collection support giving collection and item wrapper tags' do with_association_for @user, :tags, as: :check_boxes, collection_wrapper_tag: :ul, item_wrapper_tag: :li assert_select 'form ul', count: 1 assert_select 'form ul li', count: 3 end test 'builder with collection support does not change the options hash' do options = { as: :check_boxes, collection_wrapper_tag: :ul, item_wrapper_tag: :li} with_association_for @user, :tags, options assert_select 'form ul', count: 1 assert_select 'form ul li', count: 3 assert_equal({ as: :check_boxes, collection_wrapper_tag: :ul, item_wrapper_tag: :li}, options) end end simple-form-3.2.0/test/form_builder/general_test.rb0000644000175000017500000004071012623141213022606 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' class FormBuilderTest < ActionView::TestCase def with_custom_form_for(object, *args, &block) with_concat_custom_form_for(object) do |f| f.input(*args, &block) end end test 'nested simple fields yields an instance of FormBuilder' do simple_form_for :user do |f| f.simple_fields_for :posts do |posts_form| assert posts_form.instance_of?(SimpleForm::FormBuilder) end end end test 'builder input is html safe' do simple_form_for @user do |f| assert f.input(:name).html_safe? end end test 'builder works without controller' do stub_any_instance ActionView::TestCase, :controller, nil do simple_form_for @user do |f| assert f.input(:name) end end end test 'builder input allows a block to configure input' do with_form_for @user, :name do text_field_tag :foo, :bar, id: :cool end assert_no_select 'input.string' assert_select 'input#cool' end test 'builder allows adding custom input mappings for default input types' do swap SimpleForm, input_mappings: { /count$/ => :integer } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.string' assert_select 'form input#user_post_count.numeric.integer' end end test 'builder does not override custom input mappings for custom collection' do swap SimpleForm, input_mappings: { /gender$/ => :check_boxes } do with_concat_form_for @user do |f| f.input :gender, collection: [:male, :female] end assert_no_select 'select option', 'Male' assert_select 'input[type=checkbox][value=male]' end end test 'builder allows to skip input_type class' do swap SimpleForm, generate_additional_classes_for: [:label, :wrapper] do with_form_for @user, :post_count assert_no_select "form input#user_post_count.integer" assert_select "form input#user_post_count" end end test 'builder allows to add additional classes only for wrapper' do swap SimpleForm, generate_additional_classes_for: [:wrapper] do with_form_for @user, :post_count assert_no_select "form input#user_post_count.string" assert_no_select "form label#user_post_count.string" assert_select "form div.input.string" end end test 'builder allows adding custom input mappings for integer input types' do swap SimpleForm, input_mappings: { /lock_version/ => :hidden } do with_form_for @user, :lock_version assert_no_select 'form input#user_lock_version.integer' assert_select 'form input#user_lock_version.hidden' end end test 'builder uses the first matching custom input map when more than one matches' do swap SimpleForm, input_mappings: { /count$/ => :integer, /^post_/ => :password } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.password' assert_select 'form input#user_post_count.numeric.integer' end end test 'builder uses the custom map only for matched attributes' do swap SimpleForm, input_mappings: { /lock_version/ => :hidden } do with_form_for @user, :post_count assert_no_select 'form input#user_post_count.hidden' assert_select 'form input#user_post_count.string' end end test 'builder allow to use numbers in the model name' do user = UserNumber1And2.build(tags: [Tag.new(nil, 'Tag1')]) with_concat_form_for(user, url: '/') do |f| f.simple_fields_for(:tags) do |tags| tags.input :name end end assert_select 'form .user_number1_and2_tags_name' assert_no_select 'form .user_number1_and2_tags_1_name' end # INPUT TYPES test 'builder generates text fields for string columns' do with_form_for @user, :name assert_select 'form input#user_name.string' end test 'builder generates text areas for text columns' do with_form_for @user, :description assert_select 'form textarea#user_description.text' end test 'builder generates a checkbox for boolean columns' do with_form_for @user, :active assert_select 'form input[type=checkbox]#user_active.boolean' end test 'builder uses integer text field for integer columns' do with_form_for @user, :age assert_select 'form input#user_age.numeric.integer' end test 'builder generates decimal text field for decimal columns' do with_form_for @user, :credit_limit assert_select 'form input#user_credit_limit.numeric.decimal' end test 'builder generates uuid fields for uuid columns' do with_form_for @user, :uuid assert_select 'form input#user_uuid.string.uuid' end test 'builder generates password fields for columns that matches password' do with_form_for @user, :password assert_select 'form input#user_password.password' end test 'builder generates country fields for columns that matches country' do with_form_for @user, :residence_country assert_select 'form select#user_residence_country.country' end test 'builder generates time_zone fields for columns that matches time_zone' do with_form_for @user, :time_zone assert_select 'form select#user_time_zone.time_zone' end test 'builder generates email fields for columns that matches email' do with_form_for @user, :email assert_select 'form input#user_email.string.email' end test 'builder generates tel fields for columns that matches phone' do with_form_for @user, :phone_number assert_select 'form input#user_phone_number.string.tel' end test 'builder generates url fields for columns that matches url' do with_form_for @user, :url assert_select 'form input#user_url.string.url' end test 'builder generates date select for date columns' do with_form_for @user, :born_at assert_select 'form select#user_born_at_1i.date' end test 'builder generates time select for time columns' do with_form_for @user, :delivery_time assert_select 'form select#user_delivery_time_4i.time' end test 'builder generates datetime select for datetime columns' do with_form_for @user, :created_at assert_select 'form select#user_created_at_1i.datetime' end test 'builder generates datetime select for timestamp columns' do with_form_for @user, :updated_at assert_select 'form select#user_updated_at_1i.datetime' end test 'builder generates file for file columns' do @user.avatar = MiniTest::Mock.new @user.avatar.expect(:public_filename, true) with_form_for @user, :avatar assert_select 'form input#user_avatar.file' end test 'builder generates file for attributes that are real db columns but have file methods' do @user.home_picture = MiniTest::Mock.new @user.home_picture.expect(:mounted_as, true) with_form_for @user, :home_picture assert_select 'form input#user_home_picture.file' end test 'build generates select if a collection is given' do with_form_for @user, :age, collection: 1..60 assert_select 'form select#user_age.select' end test 'builder allows overriding default input type for text' do with_form_for @user, :name, as: :text assert_no_select 'form input#user_name' assert_select 'form textarea#user_name.text' with_form_for @user, :active, as: :radio_buttons assert_no_select 'form input[type=checkbox]' assert_select 'form input.radio_buttons[type=radio]', count: 2 with_form_for @user, :born_at, as: :string assert_no_select 'form select' assert_select 'form input#user_born_at.string' end # COMMON OPTIONS # Remove this test when SimpleForm.form_class is removed in 4.x test 'builder adds chosen form class' do ActiveSupport::Deprecation.silence do swap SimpleForm, form_class: :my_custom_class do with_form_for @user, :name assert_select 'form.my_custom_class' end end end # Remove this test when SimpleForm.form_class is removed in 4.x test 'builder adds chosen form class and default form class' do ActiveSupport::Deprecation.silence do swap SimpleForm, form_class: "my_custom_class", default_form_class: "my_default_class" do with_form_for @user, :name assert_select 'form.my_custom_class.my_default_class' end end end test 'builder adds default form class' do swap SimpleForm, default_form_class: "default_class" do with_form_for @user, :name assert_select 'form.default_class' end end test 'builder allows passing options to input' do with_form_for @user, :name, input_html: { class: 'my_input', id: 'my_input' } assert_select 'form input#my_input.my_input.string' end test 'builder does not propagate input options to wrapper' do with_form_for @user, :name, input_html: { class: 'my_input', id: 'my_input' } assert_no_select 'form div.input.my_input.string' assert_select 'form input#my_input.my_input.string' end test 'builder does not propagate input options to wrapper with custom wrapper' do swap_wrapper :default, custom_wrapper_with_wrapped_input do with_form_for @user, :name, input_html: { class: 'my_input' } assert_no_select 'form div.input.my_input' assert_select 'form input.my_input.string' end end test 'builder does not propagate label options to wrapper with custom wrapper' do swap_wrapper :default, custom_wrapper_with_wrapped_label do with_form_for @user, :name, label_html: { class: 'my_label' } assert_no_select 'form div.label.my_label' assert_select 'form label.my_label.string' end end test 'builder generates an input with label' do with_form_for @user, :name assert_select 'form label.string[for=user_name]', /Name/ end test 'builder is able to disable the label for an input' do with_form_for @user, :name, label: false assert_no_select 'form label' end test 'builder is able to disable the label for an input and return a html safe string' do with_form_for @user, :name, label: false, wrapper: custom_wrapper_with_wrapped_label_input assert_select 'form input#user_name' end test 'builder uses custom label' do with_form_for @user, :name, label: 'Yay!' assert_select 'form label', /Yay!/ end test 'builder passes options to label' do with_form_for @user, :name, label_html: { id: "cool" } assert_select 'form label#cool', /Name/ end test 'builder does not generate hints for an input' do with_form_for @user, :name assert_no_select 'span.hint' end test 'builder is able to add a hint for an input' do with_form_for @user, :name, hint: 'test' assert_select 'span.hint', 'test' end test 'builder is able to disable a hint even if it exists in i18n' do store_translations(:en, simple_form: { hints: { name: 'Hint test' } }) do stub_any_instance(SimpleForm::Inputs::Base, :hint, -> { raise 'Never' }) do with_form_for @user, :name, hint: false assert_no_select 'span.hint' end end end test 'builder passes options to hint' do with_form_for @user, :name, hint: 'test', hint_html: { id: "cool" } assert_select 'span.hint#cool', 'test' end test 'builder generates errors for attribute without errors' do with_form_for @user, :credit_limit assert_no_select 'span.errors' end test 'builder generates errors for attribute with errors' do with_form_for @user, :name assert_select 'span.error', "cannot be blank" end test 'builder is able to disable showing errors for an input' do with_form_for @user, :name, error: false assert_no_select 'span.error' end test 'builder passes options to errors' do with_form_for @user, :name, error_html: { id: "cool" } assert_select 'span.error#cool', "cannot be blank" end test 'placeholder does not be generated when set to false' do store_translations(:en, simple_form: { placeholders: { user: { name: 'Name goes here' } } }) do with_form_for @user, :name, placeholder: false assert_no_select 'input[placeholder]' end end # DEFAULT OPTIONS [:input, :input_field].each do |method| test "builder receives a default argument and pass it to the inputs when calling '#{method}'" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class' } } do |f| f.public_send(method, :name) end assert_select 'input.default_class' end test "builder receives a default argument and pass it to the inputs without changing the defaults when calling '#{method}'" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class', id: 'default_id' } } do |f| concat(f.public_send(method, :name)) concat(f.public_send(method, :credit_limit)) end assert_select "input.string.default_class[name='user[name]']" assert_no_select "input.string[name='user[credit_limit]']" end test "builder receives a default argument and pass it to the inputs and nested form when calling '#{method}'" do @user.company = Company.new(1, 'Empresa') with_concat_form_for @user, defaults: { input_html: { class: 'default_class' } } do |f| concat(f.public_send(method, :name)) concat(f.simple_fields_for(:company) do |company_form| concat(company_form.public_send(method, :name)) end) end assert_select "input.string.default_class[name='user[name]']" assert_select "input.string.default_class[name='user[company_attributes][name]']" end end test "builder receives a default argument and pass it to the inputs when calling 'input', respecting the specific options" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class' } } do |f| f.input :name, input_html: { id: 'specific_id' } end assert_select 'input.default_class#specific_id' end test "builder receives a default argument and pass it to the inputs when calling 'input_field', respecting the specific options" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class' } } do |f| f.input_field :name, id: 'specific_id' end assert_select 'input.default_class#specific_id' end test "builder receives a default argument and pass it to the inputs when calling 'input', overwriting the defaults with specific options" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class', id: 'default_id' } } do |f| f.input :name, input_html: { id: 'specific_id' } end assert_select 'input.default_class#specific_id' end test "builder receives a default argument and pass it to the inputs when calling 'input_field', overwriting the defaults with specific options" do with_concat_form_for @user, defaults: { input_html: { class: 'default_class', id: 'default_id' } } do |f| f.input_field :name, id: 'specific_id' end assert_select 'input.default_class#specific_id' end # WITHOUT OBJECT test 'builder generates properly when object is not present' do with_form_for :project, :name assert_select 'form input.string#project_name' end test 'builder generates password fields based on attribute name when object is not present' do with_form_for :project, :password_confirmation assert_select 'form input[type=password].password#project_password_confirmation' end test 'builder generates text fields by default for all attributes when object is not present' do with_form_for :project, :created_at assert_select 'form input.string#project_created_at' with_form_for :project, :budget assert_select 'form input.string#project_budget' end test 'builder allows overriding input type when object is not present' do with_form_for :project, :created_at, as: :datetime assert_select 'form select.datetime#project_created_at_1i' with_form_for :project, :budget, as: :decimal assert_select 'form input.decimal#project_budget' end # CUSTOM FORM BUILDER test 'custom builder inherits mappings' do with_custom_form_for @user, :email assert_select 'form input[type=email]#user_email.custom' end test 'form with CustomMapTypeFormBuilder uses custom map type builder' do with_concat_custom_mapping_form_for(:user) do |user| assert user.instance_of?(CustomMapTypeFormBuilder) end end test 'form with CustomMapTypeFormBuilder uses custom mapping' do with_concat_custom_mapping_form_for(:user) do |user| assert_equal SimpleForm::Inputs::StringInput, user.class.mappings[:custom_type] end end test 'form without CustomMapTypeFormBuilder does not use custom mapping' do with_concat_form_for(:user) do |user| assert_nil user.class.mappings[:custom_type] end end end simple-form-3.2.0/test/components/0000755000175000017500000000000012623141213017317 5ustar terceiroterceirosimple-form-3.2.0/test/components/label_test.rb0000644000175000017500000002674112623141213021774 0ustar terceiroterceiro# encoding: UTF-8 require 'test_helper' # Isolated tests for label without triggering f.label. class IsolatedLabelTest < ActionView::TestCase setup do SimpleForm::Inputs::Base.reset_i18n_cache :translate_required_html end def with_label_for(object, attribute_name, type, options = {}) with_concat_form_for(object) do |f| options[:reflection] = Association.new(Company, :company, {}) if options.delete(:setup_association) SimpleForm::Inputs::Base.new(f, attribute_name, nil, type, options).label end end test 'label generates a default humanized description' do with_label_for @user, :name, :string assert_select 'label[for=user_name]', /Name/ end test 'label allows a customized description' do with_label_for @user, :name, :string, label: 'My label!' assert_select 'label[for=user_name]', /My label!/ end test 'label uses human attribute name from object when available' do with_label_for @user, :description, :text assert_select 'label[for=user_description]', /User Description!/ end test 'label uses human attribute name based on association name' do with_label_for @user, :company_id, :string, setup_association: true assert_select 'label', /Company Human Name!/ end test 'label uses i18n based on model, action, and attribute to lookup translation' do @controller.action_name = "new" store_translations(:en, simple_form: { labels: { user: { new: { description: 'Nova descrição' } } } }) do with_label_for @user, :description, :text assert_select 'label[for=user_description]', /Nova descrição/ end end test 'label fallbacks to new when action is create' do @controller.action_name = "create" store_translations(:en, simple_form: { labels: { user: { new: { description: 'Nova descrição' } } } }) do with_label_for @user, :description, :text assert_select 'label[for=user_description]', /Nova descrição/ end end test 'label does not explode while looking for i18n translation when action is not set' do def @controller.action_name; nil; end assert_nothing_raised do with_label_for @user, :description, :text end assert_select 'label[for=user_description]' end test 'label uses i18n based on model and attribute to lookup translation' do store_translations(:en, simple_form: { labels: { user: { description: 'Descrição' } } }) do with_label_for @user, :description, :text assert_select 'label[for=user_description]', /Descrição/ end end test 'label uses i18n under defaults to lookup translation' do store_translations(:en, simple_form: { labels: { defaults: { age: 'Idade' } } }) do with_label_for @user, :age, :integer assert_select 'label[for=user_age]', /Idade/ end end test 'label does not use i18n label if translate is false' do swap SimpleForm, translate_labels: false do store_translations(:en, simple_form: { labels: { defaults: { age: 'Idade' } } }) do with_label_for @user, :age, :integer assert_select 'label[for=user_age]', /Age/ end end end test 'label uses i18n with lookup for association name' do store_translations(:en, simple_form: { labels: { user: { company: 'My company!' } } }) do with_label_for @user, :company_id, :string, setup_association: true assert_select 'label[for=user_company_id]', /My company!/ end end test 'label uses i18n under defaults namespace to lookup for association name' do store_translations(:en, simple_form: { labels: { defaults: { company: 'Plataformatec' } } }) do with_label_for @user, :company, :string, setup_association: true assert_select 'form label', /Plataformatec/ end end test 'label does correct i18n lookup for nested models with nested translation' do @user.company = Company.new(1, 'Empresa') store_translations(:en, simple_form: { labels: { user: { name: 'Usuario', company: { name: 'Nome da empresa' } } } }) do with_concat_form_for @user do |f| concat f.input :name concat(f.simple_fields_for(:company) do |company_form| concat(company_form.input :name) end) end assert_select 'label[for=user_name]', /Usuario/ assert_select 'label[for=user_company_attributes_name]', /Nome da empresa/ end end test 'label does correct i18n lookup for nested models with no nested translation' do @user.company = Company.new(1, 'Empresa') store_translations(:en, simple_form: { labels: { user: { name: 'Usuario' }, company: { name: 'Nome da empresa' } } }) do with_concat_form_for @user do |f| concat f.input :name concat(f.simple_fields_for(:company) do |company_form| concat(company_form.input :name) end) end assert_select 'label[for=user_name]', /Usuario/ assert_select 'label[for=user_company_attributes_name]', /Nome da empresa/ end end test 'label does correct i18n lookup for nested has_many models with no nested translation' do @user.tags = [Tag.new(1, 'Empresa')] store_translations(:en, simple_form: { labels: { user: { name: 'Usuario' }, tags: { name: 'Nome da empresa' } } }) do with_concat_form_for @user do |f| concat f.input :name concat(f.simple_fields_for(:tags, child_index: "new_index") do |tags_form| concat(tags_form.input :name) end) end assert_select 'label[for=user_name]', /Usuario/ assert_select 'label[for=user_tags_attributes_new_index_name]', /Nome da empresa/ end end test 'label has css class from type' do with_label_for @user, :name, :string assert_select 'label.string' with_label_for @user, :description, :text assert_select 'label.text' with_label_for @user, :age, :integer assert_select 'label.integer' with_label_for @user, :born_at, :date assert_select 'label.date' with_label_for @user, :created_at, :datetime assert_select 'label.datetime' end test 'label does not have css class from type when generate_additional_classes_for does not include :label' do swap SimpleForm, generate_additional_classes_for: [:wrapper, :input] do with_label_for @user, :name, :string assert_no_select 'label.string' with_label_for @user, :description, :text assert_no_select 'label.text' with_label_for @user, :age, :integer assert_no_select 'label.integer' with_label_for @user, :born_at, :date assert_no_select 'label.date' with_label_for @user, :created_at, :datetime assert_no_select 'label.datetime' end end test 'label does not generate empty css class' do swap SimpleForm, generate_additional_classes_for: [:wrapper, :input] do with_label_for @user, :name, :string assert_no_select 'label[class]' end end test 'label obtains required from ActiveModel::Validations when it is included' do with_label_for @validating_user, :name, :string assert_select 'label.required' with_label_for @validating_user, :status, :string assert_select 'label.optional' end test 'label does not obtain required from ActiveModel::Validations when generate_additional_classes_for does not include :label' do swap SimpleForm, generate_additional_classes_for: [:wrapper, :input] do with_label_for @validating_user, :name, :string assert_no_select 'label.required' with_label_for @validating_user, :status, :string assert_no_select 'label.optional' end end test 'label allows overriding required when ActiveModel::Validations is included' do with_label_for @validating_user, :name, :string, required: false assert_select 'label.optional' with_label_for @validating_user, :status, :string, required: true assert_select 'label.required' end test 'label is required by default when ActiveModel::Validations is not included' do with_label_for @user, :name, :string assert_select 'label.required' end test 'label is able to disable required when ActiveModel::Validations is not included' do with_label_for @user, :name, :string, required: false assert_no_select 'label.required' end test 'label adds required text when required' do with_label_for @user, :name, :string assert_select 'label.required abbr[title=required]', '*' end test 'label does not have required text in no required inputs' do with_label_for @user, :name, :string, required: false assert_no_select 'form label abbr' end test 'label uses i18n to find required text' do store_translations(:en, simple_form: { required: { text: 'campo requerido' } }) do with_label_for @user, :name, :string assert_select 'form label abbr[title="campo requerido"]', '*' end end test 'label uses i18n to find required mark' do store_translations(:en, simple_form: { required: { mark: '*-*' } }) do with_label_for @user, :name, :string assert_select 'form label abbr', '*-*' end end test 'label uses i18n to find required string tag' do store_translations(:en, simple_form: { required: { html: '*' } }) do with_label_for @user, :name, :string assert_no_select 'form label abbr' assert_select 'form label span.required[title=requerido]', '*' end end test 'label allows overwriting input id' do with_label_for @user, :name, :string, input_html: { id: 'my_new_id' } assert_select 'label[for=my_new_id]' end test 'label allows overwriting of for attribute' do with_label_for @user, :name, :string, label_html: { for: 'my_new_id' } assert_select 'label[for=my_new_id]' end test 'label allows overwriting of for attribute with input_html not containing id' do with_label_for @user, :name, :string, label_html: { for: 'my_new_id' }, input_html: { class: 'foo' } assert_select 'label[for=my_new_id]' end test 'label uses default input id when it was not overridden' do with_label_for @user, :name, :string, input_html: { class: 'my_new_id' } assert_select 'label[for=user_name]' end test 'label is generated properly when object is not present' do with_label_for :project, :name, :string assert_select 'label[for=project_name]', /Name/ end test 'label includes for attribute for select collection' do with_label_for @user, :sex, :select, collection: [:male, :female] assert_select 'label[for=user_sex]' end test 'label uses i18n properly when object is not present' do store_translations(:en, simple_form: { labels: { project: { name: 'Nome' } } }) do with_label_for :project, :name, :string assert_select 'label[for=project_name]', /Nome/ end end test 'label adds required by default when object is not present' do with_label_for :project, :name, :string assert_select 'label.required[for=project_name]' with_label_for :project, :description, :string, required: false assert_no_select 'label.required[for=project_description]' end test 'label adds chosen label class' do swap SimpleForm, label_class: :my_custom_class do with_label_for @user, :name, :string assert_select 'label.my_custom_class' end end test 'label strips extra classes even when label_class is nil' do swap SimpleForm, label_class: nil do with_label_for @user, :name, :string assert_select "label[class='string required']" assert_no_select "label[class='string required ']" assert_no_select "label[class=' string required']" end end end simple-form-3.2.0/lib/0000755000175000017500000000000012623141213014721 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form.rb0000644000175000017500000002154412623141213017570 0ustar terceiroterceirorequire 'action_view' require 'simple_form/action_view_extensions/form_helper' require 'simple_form/action_view_extensions/builder' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/reverse_merge' module SimpleForm extend ActiveSupport::Autoload autoload :Helpers autoload :Wrappers eager_autoload do autoload :Components autoload :ErrorNotification autoload :FormBuilder autoload :Inputs end def self.eager_load! super SimpleForm::Inputs.eager_load! SimpleForm::Components.eager_load! end CUSTOM_INPUT_DEPRECATION_WARN = <<-WARN %{name} method now accepts a `wrapper_options` argument. The method definition without the argument is deprecated and will be removed in the next Simple Form version. Change your code from: def %{name} to def %{name}(wrapper_options) See https://github.com/plataformatec/simple_form/pull/997 for more information. WARN @@configured = false def self.configured? #:nodoc: @@configured end ## CONFIGURATION OPTIONS # Method used to tidy up errors. mattr_accessor :error_method @@error_method = :first # Default tag used for error notification helper. mattr_accessor :error_notification_tag @@error_notification_tag = :p # CSS class to add for error notification helper. mattr_accessor :error_notification_class @@error_notification_class = :error_notification # Series of attemps to detect a default label method for collection. mattr_accessor :collection_label_methods @@collection_label_methods = [:to_label, :name, :title, :to_s] # Series of attemps to detect a default value method for collection. mattr_accessor :collection_value_methods @@collection_value_methods = [:id, :to_s] # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. mattr_accessor :collection_wrapper_tag @@collection_wrapper_tag = nil # You can define the class to use on all collection wrappers, defaulting to none. mattr_accessor :collection_wrapper_class @@collection_wrapper_class = nil # You can wrap each item in a collection of radio/check boxes with a tag, # defaulting to span. Please note that when using :boolean_style = :nested, # SimpleForm will force this option to be a :label. mattr_accessor :item_wrapper_tag @@item_wrapper_tag = :span # You can define the class to use on all item wrappers, defaulting to none. mattr_accessor :item_wrapper_class @@item_wrapper_class = nil # How the label text should be generated altogether with the required text. mattr_accessor :label_text @@label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } # You can define the class to be used on all labels. Defaults to none. mattr_accessor :label_class @@label_class = nil # Define the way to render check boxes / radio buttons with labels. # inline: input + label (default) # nested: label > input mattr_accessor :boolean_style @@boolean_style = :inline # DEPRECATED: You can define the class to be used on all forms. Default is # simple_form. mattr_reader :form_class @@form_class = :simple_form # You can define the default class to be used on all forms. Can be overriden # with `html: { :class }`. Defaults to none. mattr_accessor :default_form_class @@default_form_class = nil # You can define which elements should obtain additional classes. mattr_accessor :generate_additional_classes_for @@generate_additional_classes_for = [:wrapper, :label, :input] # Whether attributes are required by default or not. mattr_accessor :required_by_default @@required_by_default = true # Tell browsers whether to use default HTML5 validations (novalidate option). mattr_accessor :browser_validations @@browser_validations = true # Collection of methods to detect if a file type was given. mattr_accessor :file_methods @@file_methods = [:mounted_as, :file?, :public_filename] # Custom mappings for input types. This should be a hash containing a regexp # to match as key, and the input type that will be used when the field name # matches the regexp as value, such as { /count/ => :integer }. mattr_accessor :input_mappings @@input_mappings = nil # Custom wrappers for input types. This should be a hash containing an input # type as key and the wrapper that will be used for all inputs with specified type. # e.g { string: :string_wrapper, boolean: :boolean_wrapper } # You can also set a wrapper mapping per form basis. # e.g simple_form_for(@foo, wrapper_mappings: { check_boxes: :bootstrap_checkbox }) mattr_accessor :wrapper_mappings @@wrapper_mappings = nil # Namespaces where SimpleForm should look for custom input classes that override # default inputs. Namespaces are given as string to allow lazy loading inputs. # e.g. config.custom_inputs_namespaces << "CustomInputs" # will try to find CustomInputs::NumericInput when an :integer # field is called. mattr_accessor :custom_inputs_namespaces @@custom_inputs_namespaces = [] # Default priority for time_zone inputs. mattr_accessor :time_zone_priority @@time_zone_priority = nil # Default priority for country inputs. mattr_accessor :country_priority @@country_priority = nil # DEPRECATED: Maximum size allowed for inputs. mattr_accessor :default_input_size @@default_input_size = nil # When off, do not use translations in labels. Disabling translation in # hints and placeholders can be done manually in the wrapper API. mattr_accessor :translate_labels @@translate_labels = true # Automatically discover new inputs in Rails' autoload path. mattr_accessor :inputs_discovery @@inputs_discovery = true # Cache SimpleForm inputs discovery. mattr_accessor :cache_discovery @@cache_discovery = defined?(Rails) && !Rails.env.development? # Adds a class to each generated button, mostly for compatiblity. mattr_accessor :button_class @@button_class = 'button' # Override the default ActiveModelHelper behaviour of wrapping the input. # This gets taken care of semantically by adding an error class to the wrapper tag # containing the input. mattr_accessor :field_error_proc @@field_error_proc = proc do |html_tag, instance_tag| html_tag end # Adds a class to each generated inputs mattr_accessor :input_class @@input_class = nil # Defines if an input wrapper class should be included or not mattr_accessor :include_default_input_wrapper_class @@include_default_input_wrapper_class = true # Define the default class of the input wrapper of the boolean input. mattr_accessor :boolean_label_class @@boolean_label_class = 'checkbox' ## WRAPPER CONFIGURATION # The default wrapper to be used by the FormBuilder. mattr_accessor :default_wrapper @@default_wrapper = :default @@wrappers = {} #:nodoc: mattr_accessor :i18n_scope @@i18n_scope = 'simple_form' # Retrieves a given wrapper def self.wrapper(name) @@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}" end # Raised when fails to find a given wrapper name class WrapperNotFound < StandardError end # Define a new wrapper using SimpleForm::Wrappers::Builder # and store it in the given name. def self.wrappers(*args, &block) if block_given? options = args.extract_options! name = args.first || :default @@wrappers[name.to_s] = build(options, &block) else @@wrappers end end # Builds a new wrapper using SimpleForm::Wrappers::Builder. def self.build(options = {}) options[:tag] = :div if options[:tag].nil? builder = SimpleForm::Wrappers::Builder.new(options) yield builder SimpleForm::Wrappers::Root.new(builder.to_a, options) end wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b| b.use :html5 b.use :min_max b.use :maxlength b.use :placeholder b.optional :pattern b.optional :readonly b.use :label_input b.use :hint, wrap_with: { tag: :span, class: :hint } b.use :error, wrap_with: { tag: :span, class: :error } end def self.additional_classes_for(component) generate_additional_classes_for.include?(component) ? yield : [] end ## SETUP def self.default_input_size=(*) ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.default_input_size= is deprecated and has no effect", caller end def self.form_class=(value) ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.form_class= is deprecated and will be removed in 4.x. Use SimpleForm.default_form_class= instead", caller @@form_class = value end # Default way to setup Simple Form. Run rails generate simple_form:install # to create a fresh initializer with all configuration values. def self.setup @@configured = true yield self end end require 'simple_form/railtie' if defined?(Rails) simple-form-3.2.0/lib/generators/0000755000175000017500000000000012623141213017072 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/0000755000175000017500000000000012623141213021406 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/templates/0000755000175000017500000000000012623141213023404 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/templates/_form.html.haml0000644000175000017500000000042112623141213026311 0ustar terceiroterceiro= simple_form_for(@<%= singular_table_name %>) do |f| = f.error_notification .form-inputs <%- attributes.each do |attribute| -%> = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> <%- end -%> .form-actions = f.button :submit simple-form-3.2.0/lib/generators/simple_form/templates/_form.html.erb0000644000175000017500000000054012623141213026142 0ustar terceiroterceiro<%%= simple_form_for(@<%= singular_table_name %>) do |f| %> <%%= f.error_notification %>
<%- attributes.each do |attribute| -%> <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> <%- end -%>
<%%= f.button :submit %>
<%% end %> simple-form-3.2.0/lib/generators/simple_form/templates/_form.html.slim0000644000175000017500000000041512623141213026337 0ustar terceiroterceiro= simple_form_for(@<%= singular_table_name %>) do |f| = f.error_notification .form-inputs <%- attributes.each do |attribute| -%> = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> <%- end -%> .form-actions = f.button :submit simple-form-3.2.0/lib/generators/simple_form/templates/config/0000755000175000017500000000000012623141213024651 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/templates/config/initializers/0000755000175000017500000000000012623141213027357 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/templates/config/initializers/simple_form.rb0000644000175000017500000001437612623141213032233 0ustar terceiroterceiro# Use this setup block to configure all options available in SimpleForm. SimpleForm.setup do |config| # Wrappers are used by the form builder to generate a # complete input. You can remove any component from the # wrapper, change the order or even add your own to the # stack. The options given below are used to wrap the # whole input. config.wrappers :default, class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b| ## Extensions enabled by default # Any of these extensions can be disabled for a # given input by passing: `f.input EXTENSION_NAME => false`. # You can make any of these extensions optional by # renaming `b.use` to `b.optional`. # Determines whether to use HTML5 (:email, :url, ...) # and required attributes b.use :html5 # Calculates placeholders automatically from I18n # You can also pass a string as f.input placeholder: "Placeholder" b.use :placeholder ## Optional extensions # They are disabled unless you pass `f.input EXTENSION_NAME => true` # to the input. If so, they will retrieve the values from the model # if any exists. If you want to enable any of those # extensions by default, you can change `b.optional` to `b.use`. # Calculates maxlength from length validations for string inputs b.optional :maxlength # Calculates pattern from format validations for string inputs b.optional :pattern # Calculates min and max from length validations for numeric inputs b.optional :min_max # Calculates readonly automatically from readonly attributes b.optional :readonly ## Inputs b.use :label_input b.use :hint, wrap_with: { tag: :span, class: :hint } b.use :error, wrap_with: { tag: :span, class: :error } ## full_messages_for # If you want to display the full error message for the attribute, you can # use the component :full_error, like: # # b.use :full_error, wrap_with: { tag: :span, class: :error } end # The default wrapper to be used by the FormBuilder. config.default_wrapper = :default # Define the way to render check boxes / radio buttons with labels. # Defaults to :nested for bootstrap config. # inline: input + label # nested: label > input config.boolean_style = :nested # Default class for buttons config.button_class = 'btn' # Method used to tidy up errors. Specify any Rails Array method. # :first lists the first message for each field. # Use :to_sentence to list all errors for each field. # config.error_method = :first # Default tag used for error notification helper. config.error_notification_tag = :div # CSS class to add for error notification helper. config.error_notification_class = 'error_notification' # ID to add for error notification helper. # config.error_notification_id = nil # Series of attempts to detect a default label method for collection. # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] # Series of attempts to detect a default value method for collection. # config.collection_value_methods = [ :id, :to_s ] # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. # config.collection_wrapper_tag = nil # You can define the class to use on all collection wrappers. Defaulting to none. # config.collection_wrapper_class = nil # You can wrap each item in a collection of radio/check boxes with a tag, # defaulting to :span. # config.item_wrapper_tag = :span # You can define a class to use in all item wrappers. Defaulting to none. # config.item_wrapper_class = nil # How the label text should be generated altogether with the required text. # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } # You can define the class to use on all labels. Default is nil. # config.label_class = nil # You can define the default class to be used on forms. Can be overriden # with `html: { :class }`. Defaulting to none. # config.default_form_class = nil # You can define which elements should obtain additional classes # config.generate_additional_classes_for = [:wrapper, :label, :input] # Whether attributes are required by default (or not). Default is true. # config.required_by_default = true # Tell browsers whether to use the native HTML5 validations (novalidate form option). # These validations are enabled in SimpleForm's internal config but disabled by default # in this configuration, which is recommended due to some quirks from different browsers. # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, # change this configuration to true. config.browser_validations = false # Collection of methods to detect if a file type was given. # config.file_methods = [ :mounted_as, :file?, :public_filename ] # Custom mappings for input types. This should be a hash containing a regexp # to match as key, and the input type that will be used when the field name # matches the regexp as value. # config.input_mappings = { /count/ => :integer } # Custom wrappers for input types. This should be a hash containing an input # type as key and the wrapper that will be used for all inputs with specified type. # config.wrapper_mappings = { string: :prepend } # Namespaces where SimpleForm should look for custom input classes that # override default inputs. # config.custom_inputs_namespaces << "CustomInputs" # Default priority for time_zone inputs. # config.time_zone_priority = nil # Default priority for country inputs. # config.country_priority = nil # When false, do not use translations for labels. # config.translate_labels = true # Automatically discover new inputs in Rails' autoload path. # config.inputs_discovery = true # Cache SimpleForm inputs discovery # config.cache_discovery = !Rails.env.development? # Default class for inputs # config.input_class = nil # Define the default class of the input wrapper of the boolean input. config.boolean_label_class = 'checkbox' # Defines if the default input wrapper class should be included in radio # collection wrappers. # config.include_default_input_wrapper_class = true # Defines which i18n scope will be used in Simple Form. # config.i18n_scope = 'simple_form' end simple-form-3.2.0/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb0000755000175000017500000001177012623141213034326 0ustar terceiroterceiro# Use this setup block to configure all options available in SimpleForm. SimpleForm.setup do |config| config.error_notification_class = 'alert alert-danger' config.button_class = 'btn btn-default' config.boolean_label_class = nil config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.use :label, class: 'control-label' b.use :input, class: 'form-control' b.use :error, wrap_with: { tag: 'span', class: 'help-block' } b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :readonly b.use :label, class: 'control-label' b.use :input b.use :error, wrap_with: { tag: 'span', class: 'help-block' } b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.optional :readonly b.wrapper tag: 'div', class: 'checkbox' do |ba| ba.use :label_input end b.use :error, wrap_with: { tag: 'span', class: 'help-block' } b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.optional :readonly b.use :label, class: 'control-label' b.use :input b.use :error, wrap_with: { tag: 'span', class: 'help-block' } b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.use :label, class: 'col-sm-3 control-label' b.wrapper tag: 'div', class: 'col-sm-9' do |ba| ba.use :input, class: 'form-control' ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end end config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :readonly b.use :label, class: 'col-sm-3 control-label' b.wrapper tag: 'div', class: 'col-sm-9' do |ba| ba.use :input ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end end config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.optional :readonly b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr| wr.wrapper tag: 'div', class: 'checkbox' do |ba| ba.use :label_input end wr.use :error, wrap_with: { tag: 'span', class: 'help-block' } wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end end config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.optional :readonly b.use :label, class: 'col-sm-3 control-label' b.wrapper tag: 'div', class: 'col-sm-9' do |ba| ba.use :input ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end end config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.use :label, class: 'sr-only' b.use :input, class: 'form-control' b.use :error, wrap_with: { tag: 'span', class: 'help-block' } b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| b.use :html5 b.optional :readonly b.use :label, class: 'control-label' b.wrapper tag: 'div', class: 'form-inline' do |ba| ba.use :input, class: 'form-control' ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } end end # Wrappers for forms and inputs using the Bootstrap toolkit. # Check the Bootstrap docs (http://getbootstrap.com) # to learn about the different styles for forms and inputs, # buttons and other elements. config.default_wrapper = :vertical_form config.wrapper_mappings = { check_boxes: :vertical_radio_and_checkboxes, radio_buttons: :vertical_radio_and_checkboxes, file: :vertical_file_input, boolean: :vertical_boolean, datetime: :multi_select, date: :multi_select, time: :multi_select } end simple-form-3.2.0/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb0000644000175000017500000000717712623141213034462 0ustar terceiroterceiro# Use this setup block to configure all options available in SimpleForm. SimpleForm.setup do |config| # Don't forget to edit this file to adapt it to your needs (specially # all the grid-related classes) # # Please note that hints are commented out by default since Foundation # does't provide styles for hints. You will need to provide your own CSS styles for hints. # Uncomment them to enable hints. config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.use :label_input b.use :error, wrap_with: { tag: :small, class: :error } # b.use :hint, wrap_with: { tag: :span, class: :hint } end config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.wrapper :label_wrapper, tag: :div, class: 'small-3 columns' do |ba| ba.use :label, class: 'right inline' end b.wrapper :right_input_wrapper, tag: :div, class: 'small-9 columns' do |ba| ba.use :input ba.use :error, wrap_with: { tag: :small, class: :error } # ba.use :hint, wrap_with: { tag: :span, class: :hint } end end config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'row' do |b| b.use :html5 b.optional :readonly b.wrapper :container_wrapper, tag: 'div', class: 'small-offset-3 small-9 columns' do |ba| ba.wrapper :tag => 'label', :class => 'checkbox' do |bb| bb.use :input bb.use :label_text end ba.use :error, wrap_with: { tag: :small, class: :error } # ba.use :hint, wrap_with: { tag: :span, class: :hint } end end # Foundation does not provide a way to handle inline forms # This wrapper can be used to create an inline form # by hiding that labels on every screen sizes ('hidden-for-small-up'). # # Note that you need to adapt this wrapper to your needs. If you need a 4 # columns form then change the wrapper class to 'small-3', if you need # only two use 'small-6' and so on. config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error do |b| b.use :html5 b.use :placeholder b.optional :maxlength b.optional :pattern b.optional :min_max b.optional :readonly b.use :label, class: 'hidden-for-small-up' b.use :input b.use :error, wrap_with: { tag: :small, class: :error } # b.use :hint, wrap_with: { tag: :span, class: :hint } end # Examples of use: # - wrapper_html: {class: 'row'}, custom_wrapper_html: {class: 'column small-12'} # - custom_wrapper_html: {class: 'column small-3 end'} config.wrappers :customizable_wrapper, tag: 'div', error_class: :error do |b| b.use :html5 b.optional :readonly b.wrapper :custom_wrapper, tag: :div do |ba| ba.use :label_input end b.use :error, wrap_with: { tag: :small, class: :error } # b.use :hint, wrap_with: { tag: :span, class: :hint } end # CSS class for buttons config.button_class = 'button' # Set this to div to make the checkbox and radio properly work # otherwise simple_form adds a label tag instead of a div arround # the nested label config.item_wrapper_tag = :div # CSS class to add for error notification helper. config.error_notification_class = 'alert-box alert' # The default wrapper to be used by the FormBuilder. config.default_wrapper = :vertical_form end simple-form-3.2.0/lib/generators/simple_form/templates/config/locales/0000755000175000017500000000000012623141213026273 5ustar terceiroterceirosimple-form-3.2.0/lib/generators/simple_form/templates/config/locales/simple_form.en.yml0000644000175000017500000000150612623141213031735 0ustar terceiroterceiroen: simple_form: "yes": 'Yes' "no": 'No' required: text: 'required' mark: '*' # You can uncomment the line below if you need to overwrite the whole required html. # When using html, text and mark won't be used. # html: '*' error_notification: default_message: "Please review the problems below:" # Examples # labels: # defaults: # password: 'Password' # user: # new: # email: 'E-mail to sign in.' # edit: # email: 'E-mail.' # hints: # defaults: # username: 'User name to sign in.' # password: 'No special characters, please.' # include_blanks: # defaults: # age: 'Rather not say' # prompts: # defaults: # age: 'Select your age' simple-form-3.2.0/lib/generators/simple_form/templates/README0000644000175000017500000000100212623141213024255 0ustar terceiroterceiro=============================================================================== Be sure to have a copy of the Bootstrap stylesheet available on your application, you can get it on http://getbootstrap.com/. Inside your views, use the 'simple_form_for' with one of the Bootstrap form classes, '.form-horizontal' or '.form-inline', as the following: = simple_form_for(@user, html: { class: 'form-horizontal' }) do |form| =============================================================================== simple-form-3.2.0/lib/generators/simple_form/install_generator.rb0000644000175000017500000000300512623141213025445 0ustar terceiroterceiromodule SimpleForm module Generators class InstallGenerator < Rails::Generators::Base desc "Copy SimpleForm default files" source_root File.expand_path('../templates', __FILE__) class_option :template_engine, desc: 'Template engine to be invoked (erb, haml or slim).' class_option :bootstrap, type: :boolean, desc: 'Add the Bootstrap wrappers to the SimpleForm initializer.' class_option :foundation, type: :boolean, desc: 'Add the Zurb Foundation 5 wrappers to the SimpleForm initializer.' def info_bootstrap return if options.bootstrap? || options.foundation? puts "SimpleForm 3 supports Bootstrap and Zurb Foundation 5. If you want "\ "a configuration that is compatible with one of these frameworks, then please " \ "re-run this generator with --bootstrap or --foundation as an option." end def copy_config template "config/initializers/simple_form.rb" if options[:bootstrap] template "config/initializers/simple_form_bootstrap.rb" elsif options[:foundation] template "config/initializers/simple_form_foundation.rb" end directory 'config/locales' end def copy_scaffold_template engine = options[:template_engine] copy_file "_form.html.#{engine}", "lib/templates/#{engine}/scaffold/_form.html.#{engine}" end def show_readme if behavior == :invoke && options.bootstrap? readme "README" end end end end end simple-form-3.2.0/lib/generators/simple_form/USAGE0000644000175000017500000000020512623141213022172 0ustar terceiroterceiroTo copy a SimpleForm initializer to your Rails App, with some configuration values, just do: rails generate simple_form:install simple-form-3.2.0/lib/simple_form/0000755000175000017500000000000012623141213017235 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/error_notification.rb0000644000175000017500000000214312623141213023461 0ustar terceiroterceiromodule SimpleForm class ErrorNotification delegate :object, :object_name, :template, to: :@builder def initialize(builder, options) @builder = builder @message = options.delete(:message) @options = options end def render if has_errors? template.content_tag(error_notification_tag, error_message, html_options) end end protected def errors object.errors end def has_errors? object && object.respond_to?(:errors) && errors.present? end def error_message (@message || translate_error_notification).html_safe end def error_notification_tag SimpleForm.error_notification_tag end def html_options @options[:class] = "#{SimpleForm.error_notification_class} #{@options[:class]}".strip @options end def translate_error_notification lookups = [] lookups << :"#{object_name}" lookups << :default_message lookups << "Please review the problems below:" I18n.t(lookups.shift, scope: :"simple_form.error_notification", default: lookups) end end end simple-form-3.2.0/lib/simple_form/railtie.rb0000644000175000017500000000065512623141213021221 0ustar terceiroterceirorequire 'rails/railtie' module SimpleForm class Railtie < Rails::Railtie config.eager_load_namespaces << SimpleForm config.after_initialize do unless SimpleForm.configured? warn '[Simple Form] Simple Form is not configured in the application and will use the default values.' + ' Use `rails generate simple_form:install` to generate the Simple Form configuration.' end end end end simple-form-3.2.0/lib/simple_form/inputs.rb0000644000175000017500000000110212623141213021076 0ustar terceiroterceiromodule SimpleForm module Inputs extend ActiveSupport::Autoload autoload :Base autoload :BlockInput autoload :BooleanInput autoload :CollectionCheckBoxesInput autoload :CollectionInput autoload :CollectionRadioButtonsInput autoload :CollectionSelectInput autoload :DateTimeInput autoload :FileInput autoload :GroupedCollectionSelectInput autoload :HiddenInput autoload :NumericInput autoload :PasswordInput autoload :PriorityInput autoload :RangeInput autoload :StringInput autoload :TextInput end end simple-form-3.2.0/lib/simple_form/action_view_extensions/0000755000175000017500000000000012623141213024023 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/action_view_extensions/form_helper.rb0000644000175000017500000000436612623141213026663 0ustar terceiroterceiromodule SimpleForm module ActionViewExtensions # This module creates SimpleForm wrappers around default form_for and fields_for. # # Example: # # simple_form_for @user do |f| # f.input :name, hint: 'My hint' # end # module FormHelper def simple_form_for(record, options = {}, &block) options[:builder] ||= SimpleForm::FormBuilder options[:html] ||= {} unless options[:html].key?(:novalidate) options[:html][:novalidate] = !SimpleForm.browser_validations end if options[:html].key?(:class) options[:html][:class] = [SimpleForm.form_class, options[:html][:class]].compact else options[:html][:class] = [SimpleForm.form_class, SimpleForm.default_form_class, simple_form_css_class(record, options)].compact end with_simple_form_field_error_proc do form_for(record, options, &block) end end def simple_fields_for(record_name, record_object = nil, options = {}, &block) options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options? options[:builder] ||= SimpleForm::FormBuilder with_simple_form_field_error_proc do fields_for(record_name, record_object, options, &block) end end private def with_simple_form_field_error_proc default_field_error_proc = ::ActionView::Base.field_error_proc begin ::ActionView::Base.field_error_proc = SimpleForm.field_error_proc yield ensure ::ActionView::Base.field_error_proc = default_field_error_proc end end def simple_form_css_class(record, options) html_options = options[:html] as = options[:as] if html_options.key?(:class) html_options[:class] elsif record.is_a?(String) || record.is_a?(Symbol) as || record else record = record.last if record.is_a?(Array) action = record.respond_to?(:persisted?) && record.persisted? ? :edit : :new as ? "#{action}_#{as}" : dom_class(record, action) end end end end end ActionView::Base.send :include, SimpleForm::ActionViewExtensions::FormHelper simple-form-3.2.0/lib/simple_form/action_view_extensions/builder.rb0000644000175000017500000000225012623141213025775 0ustar terceiroterceiromodule SimpleForm module ActionViewExtensions # A collection of methods required by simple_form but added to rails default form. # This means that you can use such methods outside simple_form context. module Builder # Wrapper for using SimpleForm inside a default rails form. # Example: # # form_for @user do |f| # f.simple_fields_for :posts do |posts_form| # # Here you have all simple_form methods available # posts_form.input :title # end # end def simple_fields_for(*args, &block) options = args.extract_options! options[:wrapper] = self.options[:wrapper] if options[:wrapper].nil? options[:defaults] ||= self.options[:defaults] options[:wrapper_mappings] ||= self.options[:wrapper_mappings] if self.class < ActionView::Helpers::FormBuilder options[:builder] ||= self.class else options[:builder] ||= SimpleForm::FormBuilder end fields_for(*args, options, &block) end end end end module ActionView::Helpers class FormBuilder include SimpleForm::ActionViewExtensions::Builder end end simple-form-3.2.0/lib/simple_form/wrappers/0000755000175000017500000000000012623141213021100 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/wrappers/leaf.rb0000644000175000017500000000107712623141213022341 0ustar terceiroterceiromodule SimpleForm module Wrappers class Leaf attr_reader :namespace def initialize(namespace, options = {}) @namespace = namespace @options = options end def render(input) method = input.method(@namespace) if method.arity == 0 ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: @namespace }) method.call else method.call(@options) end end def find(name) self if @namespace == name end end end end simple-form-3.2.0/lib/simple_form/wrappers/builder.rb0000644000175000017500000000513612623141213023060 0ustar terceiroterceiromodule SimpleForm module Wrappers # Provides the builder syntax for components. The builder provides # three methods `use`, `optional` and `wrapper` and they allow the following invocations: # # config.wrappers do |b| # # Use a single component # b.use :html5 # # # Use the component, but do not automatically lookup. It will only be triggered when # # :placeholder is explicitly set. # b.optional :placeholder # # # Use a component with specific wrapper options # b.use :error, wrap_with: { tag: "span", class: "error" } # # # Use a set of components by wrapping them in a tag+class. # b.wrapper tag: "div", class: "another" do |ba| # ba.use :label # ba.use :input # end # # # Use a set of components by wrapping them in a tag+class. # # This wrapper is identified by :label_input, which means it can # # be turned off on demand with `f.input :name, label_input: false` # b.wrapper :label_input, tag: "div", class: "another" do |ba| # ba.use :label # ba.use :input # end # end # # The builder also accepts default options at the root level. This is usually # used if you want a component to be disabled by default: # # config.wrappers hint: false do |b| # b.use :hint # b.use :label_input # end # # In the example above, hint defaults to false, which means it won't automatically # do the lookup anymore. It will only be triggered when :hint is explicitly set. class Builder def initialize(options) @options = options @components = [] end def use(name, options = {}) if options && wrapper = options[:wrap_with] @components << Single.new(name, wrapper, options.except(:wrap_with)) else @components << Leaf.new(name, options) end end def optional(name, options = {}, &block) @options[name] = false use(name, options) end def wrapper(name, options = nil) if block_given? name, options = nil, name if name.is_a?(Hash) builder = self.class.new(@options) options ||= {} options[:tag] = :div if options[:tag].nil? yield builder @components << Many.new(name, builder.to_a, options) else raise ArgumentError, "A block is required as argument to wrapper" end end def to_a @components end end end end simple-form-3.2.0/lib/simple_form/wrappers/single.rb0000644000175000017500000000121712623141213022707 0ustar terceiroterceiromodule SimpleForm module Wrappers # `Single` is an optimization for a wrapper that has only one component. class Single < Many def initialize(name, wrapper_options = {}, options = {}) @component = Leaf.new(name, options) super(name, [@component], wrapper_options) end def render(input) options = input.options if options[namespace] != false content = @component.render(input) wrap(input, options, content) if content end end private def html_options(options) [:label, :input].include?(namespace) ? {} : super end end end end simple-form-3.2.0/lib/simple_form/wrappers/many.rb0000644000175000017500000000424512623141213022376 0ustar terceiroterceiromodule SimpleForm module Wrappers # A wrapper is an object that holds several components and render them. # A component may be any object that responds to `render`. # This API allows inputs/components to be easily wrapped, removing the # need to modify the code only to wrap input in an extra tag. # # `Many` represents a wrapper around several components at the same time. # It may optionally receive a namespace, allowing it to be configured # on demand on input generation. class Many attr_reader :namespace, :defaults, :components def initialize(namespace, components, defaults = {}) @namespace = namespace @components = components @defaults = defaults @defaults[:tag] = :div unless @defaults.key?(:tag) @defaults[:class] = Array(@defaults[:class]) end def render(input) content = "".html_safe options = input.options components.each do |component| next if options[component.namespace] == false rendered = component.render(input) content.safe_concat rendered.to_s if rendered end wrap(input, options, content) end def find(name) return self if namespace == name @components.each do |c| if c.is_a?(Symbol) return nil if c == namespace elsif value = c.find(name) return value end end nil end private def wrap(input, options, content) return content if options[namespace] == false return if defaults[:unless_blank] && content.empty? tag = (namespace && options[:"#{namespace}_tag"]) || @defaults[:tag] return content unless tag klass = html_classes(input, options) opts = html_options(options) opts[:class] = (klass << opts[:class]).join(' ').strip unless klass.empty? input.template.content_tag(tag, content, opts) end def html_options(options) (@defaults[:html] || {}).merge(options[:"#{namespace}_html"] || {}) end def html_classes(input, options) @defaults[:class].dup end end end end simple-form-3.2.0/lib/simple_form/wrappers/root.rb0000644000175000017500000000215612623141213022414 0ustar terceiroterceiromodule SimpleForm module Wrappers # `Root` is the root wrapper for all components. It is special cased to # always have a namespace and to add special html classes. class Root < Many attr_reader :options def initialize(*args) super(:wrapper, *args) @options = @defaults.except(:tag, :class, :error_class, :hint_class) end def render(input) input.options.reverse_merge!(@options) super end # Provide a fallback if name cannot be found. def find(name) super || SimpleForm::Wrappers::Many.new(name, [Leaf.new(name)]) end private def html_classes(input, options) css = options[:wrapper_class] ? Array(options[:wrapper_class]) : @defaults[:class] css += SimpleForm.additional_classes_for(:wrapper) do input.additional_classes + [input.input_class] end css << (options[:wrapper_error_class] || @defaults[:error_class]) if input.has_errors? css << (options[:wrapper_hint_class] || @defaults[:hint_class]) if input.has_hint? css.compact end end end end simple-form-3.2.0/lib/simple_form/inputs/0000755000175000017500000000000012623141213020557 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/inputs/file_input.rb0000644000175000017500000000043512623141213023244 0ustar terceiroterceiromodule SimpleForm module Inputs class FileInput < Base def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.file_field(attribute_name, merged_input_options) end end end end simple-form-3.2.0/lib/simple_form/inputs/collection_input.rb0000644000175000017500000001001612623141213024454 0ustar terceiroterceiromodule SimpleForm module Inputs class CollectionInput < Base # Default boolean collection for use with selects/radios when no # collection is given. Always fallback to this boolean collection. # Texts can be translated using i18n in "simple_form.yes" and # "simple_form.no" keys. See the example locale file. def self.boolean_collection i18n_cache :boolean_collection do [ [I18n.t(:"simple_form.yes", default: 'Yes'), true], [I18n.t(:"simple_form.no", default: 'No'), false] ] end end def input(wrapper_options = nil) raise NotImplementedError, "input should be implemented by classes inheriting from CollectionInput" end def input_options options = super options[:include_blank] = true unless skip_include_blank? translate_option options, :prompt translate_option options, :include_blank options end private def collection @collection ||= begin collection = options.delete(:collection) || self.class.boolean_collection collection.respond_to?(:call) ? collection.call : collection.to_a end end def has_required? super && (input_options[:include_blank] || input_options[:prompt] || multiple?) end # Check if :include_blank must be included by default. def skip_include_blank? (options.keys & [:prompt, :include_blank, :default, :selected]).any? || multiple? end def multiple? !!options[:input_html].try(:[], :multiple) end # Detect the right method to find the label and value for a collection. # If no label or value method are defined, will attempt to find them based # on default label and value methods that can be configured through # SimpleForm.collection_label_methods and # SimpleForm.collection_value_methods. def detect_collection_methods label, value = options.delete(:label_method), options.delete(:value_method) unless label && value common_method_for = detect_common_display_methods label ||= common_method_for[:label] value ||= common_method_for[:value] end [label, value] end def detect_common_display_methods(collection_classes = detect_collection_classes) collection_translated = translate_collection if collection_classes == [Symbol] if collection_translated || collection_classes.include?(Array) { label: :first, value: :second } elsif collection_includes_basic_objects?(collection_classes) { label: :to_s, value: :to_s } else detect_method_from_class(collection_classes) end end def detect_method_from_class(collection_classes) sample = collection.first || collection.last { label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) }, value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } } end def detect_collection_classes(some_collection = collection) some_collection.map { |e| e.class }.uniq end def collection_includes_basic_objects?(collection_classes) (collection_classes & [ String, Integer, Fixnum, Bignum, Float, NilClass, Symbol, TrueClass, FalseClass ]).any? end def translate_collection if translated_collection = translate_from_namespace(:options) @collection = collection.map do |key| html_key = "#{key}_html".to_sym if translated_collection[html_key] [translated_collection[html_key].html_safe || key, key.to_s] else [translated_collection[key] || key, key.to_s] end end true end end def translate_option(options, key) if options[key] == :translate namespace = key.to_s.pluralize options[key] = translate_from_namespace(namespace, true) end end end end end simple-form-3.2.0/lib/simple_form/inputs/priority_input.rb0000644000175000017500000000117312623141213024206 0ustar terceiroterceiromodule SimpleForm module Inputs class PriorityInput < CollectionSelectInput def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.send(:"#{input_type}_select", attribute_name, input_priority, input_options, merged_input_options) end def input_priority options[:priority] || SimpleForm.send(:"#{input_type}_priority") end protected def has_required? false end def skip_include_blank? super || input_priority.present? end end end end simple-form-3.2.0/lib/simple_form/inputs/collection_select_input.rb0000644000175000017500000000072012623141213026014 0ustar terceiroterceiromodule SimpleForm module Inputs class CollectionSelectInput < CollectionInput def input(wrapper_options = nil) label_method, value_method = detect_collection_methods merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.collection_select( attribute_name, collection, value_method, label_method, input_options, merged_input_options ) end end end end simple-form-3.2.0/lib/simple_form/inputs/text_input.rb0000644000175000017500000000050312623141213023305 0ustar terceiroterceiromodule SimpleForm module Inputs class TextInput < Base enable :placeholder, :maxlength def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.text_area(attribute_name, merged_input_options) end end end end simple-form-3.2.0/lib/simple_form/inputs/date_time_input.rb0000644000175000017500000000176012623141213024262 0ustar terceiroterceiromodule SimpleForm module Inputs class DateTimeInput < Base def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) if use_html5_inputs? @builder.send(:"#{input_type}_field", attribute_name, merged_input_options) else @builder.send(:"#{input_type}_select", attribute_name, input_options, merged_input_options) end end private def label_target if use_html5_inputs? attribute_name else position = case input_type when :date, :datetime date_order = input_options[:order] || I18n.t('date.order') date_order.first.to_sym else :hour end position = ActionView::Helpers::DateTimeSelector::POSITION[position] "#{attribute_name}_#{position}i" end end def use_html5_inputs? input_options[:html5] end end end end simple-form-3.2.0/lib/simple_form/inputs/block_input.rb0000644000175000017500000000036712623141213023423 0ustar terceiroterceiromodule SimpleForm module Inputs class BlockInput < Base def initialize(*args, &block) super @block = block end def input(wrapper_options = nil) template.capture(&@block) end end end end simple-form-3.2.0/lib/simple_form/inputs/base.rb0000644000175000017500000001542712623141213022027 0ustar terceiroterceirorequire 'simple_form/i18n_cache' require 'active_support/core_ext/string/output_safety' require 'action_view/helpers' module SimpleForm module Inputs class Base include ERB::Util include ActionView::Helpers::TranslationHelper extend I18nCache include SimpleForm::Helpers::Autofocus include SimpleForm::Helpers::Disabled include SimpleForm::Helpers::Readonly include SimpleForm::Helpers::Required include SimpleForm::Helpers::Validators include SimpleForm::Components::Errors include SimpleForm::Components::Hints include SimpleForm::Components::HTML5 include SimpleForm::Components::LabelInput include SimpleForm::Components::Maxlength include SimpleForm::Components::MinMax include SimpleForm::Components::Pattern include SimpleForm::Components::Placeholders include SimpleForm::Components::Readonly attr_reader :attribute_name, :column, :input_type, :reflection, :options, :input_html_options, :input_html_classes, :html_classes delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder class_attribute :default_options self.default_options = {} def self.enable(*keys) options = self.default_options.dup keys.each { |key| options.delete(key) } self.default_options = options end def self.disable(*keys) options = self.default_options.dup keys.each { |key| options[key] = false } self.default_options = options end # Always enabled. enable :hint # Usually disabled, needs to be enabled explicitly passing true as option. disable :maxlength, :placeholder, :pattern, :min_max def initialize(builder, attribute_name, column, input_type, options = {}) super options = options.dup @builder = builder @attribute_name = attribute_name @column = column @input_type = input_type @reflection = options.delete(:reflection) @options = options.reverse_merge!(self.class.default_options) @required = calculate_required # Notice that html_options_for receives a reference to input_html_classes. # This means that classes added dynamically to input_html_classes will # still propagate to input_html_options. @html_classes = SimpleForm.additional_classes_for(:input) { additional_classes } @input_html_classes = @html_classes.dup if SimpleForm.input_class && !input_html_classes.empty? input_html_classes << SimpleForm.input_class end @input_html_options = html_options_for(:input, input_html_classes).tap do |o| o[:readonly] = true if has_readonly? o[:disabled] = true if has_disabled? o[:autofocus] = true if has_autofocus? end end def input(wrapper_options = nil) raise NotImplementedError end def input_options options end def additional_classes @additional_classes ||= [input_type, required_class, readonly_class, disabled_class].compact end def input_class "#{lookup_model_names.join("_")}_#{reflection_or_attribute_name}" end private def limit if column decimal_or_float? ? decimal_limit : column_limit end end def column_limit column.limit end # Add one for decimal point def decimal_limit column_limit && (column_limit + 1) end def decimal_or_float? column.number? && column.type != :integer end def nested_boolean_style? options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested end # Find reflection name when available, otherwise use attribute def reflection_or_attribute_name @reflection_or_attribute_name ||= reflection ? reflection.name : attribute_name end # Retrieve options for the given namespace from the options hash def html_options_for(namespace, css_classes) html_options = options[:"#{namespace}_html"] html_options = html_options ? html_options.dup : {} css_classes << html_options[:class] if html_options.key?(:class) html_options[:class] = css_classes unless css_classes.empty? html_options end # Lookup translations for the given namespace using I18n, based on object name, # actual action and attribute name. Lookup priority as follows: # # simple_form.{namespace}.{model}.{action}.{attribute} # simple_form.{namespace}.{model}.{attribute} # simple_form.{namespace}.defaults.{attribute} # # Namespace is used for :labels and :hints. # # Model is the actual object name, for a @user object you'll have :user. # Action is the action being rendered, usually :new or :edit. # And attribute is the attribute itself, :name for example. # # The lookup for nested attributes is also done in a nested format using # both model and nested object names, such as follow: # # simple_form.{namespace}.{model}.{nested}.{action}.{attribute} # simple_form.{namespace}.{model}.{nested}.{attribute} # simple_form.{namespace}.{nested}.{action}.{attribute} # simple_form.{namespace}.{nested}.{attribute} # simple_form.{namespace}.defaults.{attribute} # # Example: # # simple_form: # labels: # user: # new: # email: 'E-mail para efetuar o sign in.' # edit: # email: 'E-mail.' # # Take a look at our locale example file. def translate_from_namespace(namespace, default = '') model_names = lookup_model_names.dup lookups = [] while !model_names.empty? joined_model_names = model_names.join(".") model_names.shift lookups << :"#{joined_model_names}.#{lookup_action}.#{reflection_or_attribute_name}" lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}" end lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}" lookups << :"defaults.#{reflection_or_attribute_name}" lookups << default I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence end def merge_wrapper_options(options, wrapper_options) if wrapper_options options.merge(wrapper_options) do |_, oldval, newval| if Array === oldval oldval + Array(newval) end end else options end end def i18n_scope SimpleForm.i18n_scope end end end end simple-form-3.2.0/lib/simple_form/inputs/range_input.rb0000644000175000017500000000042012623141213023413 0ustar terceiroterceiromodule SimpleForm module Inputs class RangeInput < NumericInput def input(wrapper_options = nil) if html5? input_html_options[:type] ||= "range" input_html_options[:step] ||= 1 end super end end end end simple-form-3.2.0/lib/simple_form/inputs/boolean_input.rb0000644000175000017500000000643712623141213023754 0ustar terceiroterceiromodule SimpleForm module Inputs class BooleanInput < Base def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) if nested_boolean_style? build_hidden_field_for_checkbox + template.label_tag(nil, class: SimpleForm.boolean_label_class) { build_check_box_without_hidden_field(merged_input_options) + inline_label } else build_check_box(unchecked_value, merged_input_options) end end def label_input(wrapper_options = nil) if options[:label] == false || inline_label? input(wrapper_options) elsif nested_boolean_style? html_options = label_html_options.dup html_options[:class] ||= [] html_options[:class].push(SimpleForm.boolean_label_class) if SimpleForm.boolean_label_class merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) build_hidden_field_for_checkbox + @builder.label(label_target, html_options) { build_check_box_without_hidden_field(merged_input_options) + label_text } else input(wrapper_options) + label(wrapper_options) end end private # Build a checkbox tag using default unchecked value. This allows us to # reuse the method for nested boolean style, but with no unchecked value, # which won't generate the hidden checkbox. This is the default functionality # in Rails > 3.2.1, and is backported in SimpleForm AV helpers. def build_check_box(unchecked_value, options) @builder.check_box(attribute_name, options, checked_value, unchecked_value) end # Build a checkbox without generating the hidden field. See # #build_hidden_field_for_checkbox for more info. def build_check_box_without_hidden_field(options) build_check_box(nil, options) end # Create a hidden field for the current checkbox, so we can simulate Rails # functionality with hidden + checkbox, but under a nested context, where # we need the hidden field to be *outside* the label (otherwise it # generates invalid html - html5 only). def build_hidden_field_for_checkbox options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] } options[:name] = input_html_options[:name] if input_html_options.has_key?(:name) @builder.hidden_field(attribute_name, options) end def inline_label? nested_boolean_style? && options[:inline_label] end def inline_label inline_option = options[:inline_label] if inline_option label = inline_option == true ? label_text : html_escape(inline_option) " #{label}".html_safe end end # Booleans are not required by default because in most of the cases # it makes no sense marking them as required. The only exception is # Terms of Use usually presented at most sites sign up screen. def required_by_default? false end def checked_value options.fetch(:checked_value, '1') end def unchecked_value options.fetch(:unchecked_value, '0') end end end end simple-form-3.2.0/lib/simple_form/inputs/collection_check_boxes_input.rb0000644000175000017500000000103412623141213027011 0ustar terceiroterceiromodule SimpleForm module Inputs class CollectionCheckBoxesInput < CollectionRadioButtonsInput protected # Checkbox components do not use the required html tag. # More info: https://github.com/plataformatec/simple_form/issues/340#issuecomment-2871956 def has_required? false end def build_nested_boolean_style_item_tag(collection_builder) collection_builder.check_box + collection_builder.text end def item_wrapper_class "checkbox" end end end end simple-form-3.2.0/lib/simple_form/inputs/hidden_input.rb0000644000175000017500000000062112623141213023555 0ustar terceiroterceiromodule SimpleForm module Inputs class HiddenInput < Base disable :label, :errors, :hint, :required def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.hidden_field(attribute_name, merged_input_options) end private def required_class nil end end end end simple-form-3.2.0/lib/simple_form/inputs/grouped_collection_select_input.rb0000644000175000017500000000330012623141213027536 0ustar terceiroterceiromodule SimpleForm module Inputs class GroupedCollectionSelectInput < CollectionInput def input(wrapper_options = nil) label_method, value_method = detect_collection_methods merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.grouped_collection_select(attribute_name, grouped_collection, group_method, group_label_method, value_method, label_method, input_options, merged_input_options) end private def grouped_collection @grouped_collection ||= begin grouped_collection = options.delete(:collection) grouped_collection.respond_to?(:call) ? grouped_collection.call : grouped_collection.to_a end end # Sample collection def collection @collection ||= grouped_collection.map { |collection| collection.try(:send, group_method) }.detect(&:present?) || [] end def group_method @group_method ||= options.delete(:group_method) end def group_label_method label = options.delete(:group_label_method) unless label common_method_for = detect_common_display_methods(detect_collection_classes(grouped_collection)) label = common_method_for[:label] end label end def detect_method_from_class(collection_classes) return {} if collection_classes.empty? sample = collection_classes.first { label: SimpleForm.collection_label_methods.find { |m| sample.instance_methods.include?(m) }, value: SimpleForm.collection_value_methods.find { |m| sample.instance_methods.include?(m) } } end end end end simple-form-3.2.0/lib/simple_form/inputs/string_input.rb0000644000175000017500000000105212623141213023627 0ustar terceiroterceiromodule SimpleForm module Inputs class StringInput < Base enable :placeholder, :maxlength, :pattern def input(wrapper_options = nil) unless string? input_html_classes.unshift("string") input_html_options[:type] ||= input_type if html5? end merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.text_field(attribute_name, merged_input_options) end private def string? input_type == :string end end end end simple-form-3.2.0/lib/simple_form/inputs/collection_radio_buttons_input.rb0000644000175000017500000000365412623141213027422 0ustar terceiroterceiromodule SimpleForm module Inputs class CollectionRadioButtonsInput < CollectionInput def input(wrapper_options = nil) label_method, value_method = detect_collection_methods merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.send(:"collection_#{input_type}", attribute_name, collection, value_method, label_method, input_options, merged_input_options, &collection_block_for_nested_boolean_style ) end def input_options options = super apply_default_collection_options!(options) options end protected def apply_default_collection_options!(options) options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag) options[:item_wrapper_class] = [ item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class ].compact.presence if SimpleForm.include_default_input_wrapper_class options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag) options[:collection_wrapper_class] = [ options[:collection_wrapper_class], SimpleForm.collection_wrapper_class ].compact.presence end def collection_block_for_nested_boolean_style return unless nested_boolean_style? proc { |builder| build_nested_boolean_style_item_tag(builder) } end def build_nested_boolean_style_item_tag(collection_builder) collection_builder.radio_button + collection_builder.text end def item_wrapper_class "radio" end # Do not attempt to generate label[for] attributes by default, unless an # explicit html option is given. This avoids generating labels pointing to # non existent fields. def generate_label_for_attribute? false end end end end simple-form-3.2.0/lib/simple_form/inputs/password_input.rb0000644000175000017500000000051412623141213024165 0ustar terceiroterceiromodule SimpleForm module Inputs class PasswordInput < Base enable :placeholder, :maxlength def input(wrapper_options = nil) merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.password_field(attribute_name, merged_input_options) end end end end simple-form-3.2.0/lib/simple_form/inputs/numeric_input.rb0000644000175000017500000000100012623141213023754 0ustar terceiroterceiromodule SimpleForm module Inputs class NumericInput < Base enable :placeholder, :min_max def input(wrapper_options = nil) input_html_classes.unshift("numeric") if html5? input_html_options[:type] ||= "number" input_html_options[:step] ||= integer? ? 1 : "any" end merged_input_options = merge_wrapper_options(input_html_options, wrapper_options) @builder.text_field(attribute_name, merged_input_options) end end end end simple-form-3.2.0/lib/simple_form/version.rb0000644000175000017500000000006112623141213021244 0ustar terceiroterceiromodule SimpleForm VERSION = "3.2.0".freeze end simple-form-3.2.0/lib/simple_form/form_builder.rb0000644000175000017500000006027012623141213022240 0ustar terceiroterceirorequire 'active_support/core_ext/object/deep_dup' require 'simple_form/map_type' require 'simple_form/tags' module SimpleForm class FormBuilder < ActionView::Helpers::FormBuilder attr_reader :template, :object_name, :object, :wrapper # When action is create or update, we still should use new and edit ACTIONS = { 'create' => 'new', 'update' => 'edit' } ATTRIBUTE_COMPONENTS = [:html5, :min_max, :maxlength, :placeholder, :pattern, :readonly] extend MapType include SimpleForm::Inputs map_type :text, to: SimpleForm::Inputs::TextInput map_type :file, to: SimpleForm::Inputs::FileInput map_type :string, :email, :search, :tel, :url, :uuid, to: SimpleForm::Inputs::StringInput map_type :password, to: SimpleForm::Inputs::PasswordInput map_type :integer, :decimal, :float, to: SimpleForm::Inputs::NumericInput map_type :range, to: SimpleForm::Inputs::RangeInput map_type :check_boxes, to: SimpleForm::Inputs::CollectionCheckBoxesInput map_type :radio_buttons, to: SimpleForm::Inputs::CollectionRadioButtonsInput map_type :select, to: SimpleForm::Inputs::CollectionSelectInput map_type :grouped_select, to: SimpleForm::Inputs::GroupedCollectionSelectInput map_type :date, :time, :datetime, to: SimpleForm::Inputs::DateTimeInput map_type :country, :time_zone, to: SimpleForm::Inputs::PriorityInput map_type :boolean, to: SimpleForm::Inputs::BooleanInput map_type :hidden, to: SimpleForm::Inputs::HiddenInput def self.discovery_cache @discovery_cache ||= {} end def initialize(*) #:nodoc: super @defaults = options[:defaults] @wrapper = SimpleForm.wrapper(options[:wrapper] || SimpleForm.default_wrapper) end # Basic input helper, combines all components in the stack to generate # input html based on options the user define and some guesses through # database column information. By default a call to input will generate # label + input + hint (when defined) + errors (when exists), and all can # be configured inside a wrapper html. # # == Examples # # # Imagine @user has error "can't be blank" on name # simple_form_for @user do |f| # f.input :name, hint: 'My hint' # end # # This is the output html (only the input portion, not the form): # # # # My hint # can't be blank # # Each database type will render a default input, based on some mappings and # heuristic to determine which is the best option. # # You have some options for the input to enable/disable some functions: # # as: allows you to define the input type you want, for instance you # can use it to generate a text field for a date column. # # required: defines whether this attribute is required or not. True # by default. # # The fact SimpleForm is built in components allow the interface to be unified. # So, for instance, if you need to disable :hint for a given input, you can pass # hint: false. The same works for :error, :label and :wrapper. # # Besides the html for any component can be changed. So, if you want to change # the label html you just need to give a hash to :label_html. To configure the # input html, supply :input_html instead and so on. # # == Options # # Some inputs, as datetime, time and select allow you to give extra options, like # prompt and/or include blank. Such options are given in plainly: # # f.input :created_at, include_blank: true # # == Collection # # When playing with collections (:radio_buttons, :check_boxes and :select # inputs), you have three extra options: # # collection: use to determine the collection to generate the radio or select # # label_method: the method to apply on the array collection to get the label # # value_method: the method to apply on the array collection to get the value # # == Priority # # Some inputs, as :time_zone and :country accepts a :priority option. If none is # given SimpleForm.time_zone_priority and SimpleForm.country_priority are used respectively. # def input(attribute_name, options = {}, &block) options = @defaults.deep_dup.deep_merge(options) if @defaults input = find_input(attribute_name, options, &block) wrapper = find_wrapper(input.input_type, options) wrapper.render input end alias :attribute :input # Creates a input tag for the given attribute. All the given options # are sent as :input_html. # # == Examples # # simple_form_for @user do |f| # f.input_field :name # end # # This is the output html (only the input portion, not the form): # # # def input_field(attribute_name, options = {}) components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS) options = options.dup options[:input_html] = options.except(:as, :boolean_style, :collection, :label_method, :value_method, *components) options = @defaults.deep_dup.deep_merge(options) if @defaults input = find_input(attribute_name, options) wrapper = find_wrapper(input.input_type, options) components = components.concat([:input]).map { |component| SimpleForm::Wrappers::Leaf.new(component) } SimpleForm::Wrappers::Root.new(components, wrapper.options.merge(wrapper: false)).render input end # Helper for dealing with association selects/radios, generating the # collection automatically. It's just a wrapper to input, so all options # supported in input are also supported by association. Some extra options # can also be given: # # == Examples # # simple_form_for @user do |f| # f.association :company # Company.all # end # # f.association :company, collection: Company.all(order: 'name') # # Same as using :order option, but overriding collection # # == Block # # When a block is given, association simple behaves as a proxy to # simple_fields_for: # # f.association :company do |c| # c.input :name # c.input :type # end # # From the options above, only :collection can also be supplied. # # Please note that the association helper is currently only tested with Active Record. Depending on the ORM you are using your mileage may vary. # def association(association, options = {}, &block) options = options.dup return simple_fields_for(*[association, options.delete(:collection), options].compact, &block) if block_given? raise ArgumentError, "Association cannot be used in forms not associated with an object" unless @object reflection = find_association_reflection(association) raise "Association #{association.inspect} not found" unless reflection options[:as] ||= :select options[:collection] ||= fetch_association_collection(reflection, options) attribute = build_association_attribute(reflection, association, options) input(attribute, options.merge(reflection: reflection)) end # Creates a button: # # form_for @user do |f| # f.button :submit # end # # It just acts as a proxy to method name given. We also alias original Rails # button implementation (3.2 forward (to delegate to the original when # calling `f.button :button`. # alias_method :button_button, :button def button(type, *args, &block) options = args.extract_options!.dup options[:class] = [SimpleForm.button_class, options[:class]].compact args << options if respond_to?(:"#{type}_button") send(:"#{type}_button", *args, &block) else send(type, *args, &block) end end # Creates an error tag based on the given attribute, only when the attribute # contains errors. All the given options are sent as :error_html. # # == Examples # # f.error :name # f.error :name, id: "cool_error" # def error(attribute_name, options = {}) options = options.dup options[:error_html] = options.except(:error_tag, :error_prefix, :error_method) column = find_attribute_column(attribute_name) input_type = default_input_type(attribute_name, column, options) wrapper.find(:error). render(SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options)) end # Return the error but also considering its name. This is used # when errors for a hidden field need to be shown. # # == Examples # # f.full_error :token #=> Token is invalid # def full_error(attribute_name, options = {}) options = options.dup options[:error_prefix] ||= if object.class.respond_to?(:human_attribute_name) object.class.human_attribute_name(attribute_name.to_s) else attribute_name.to_s.humanize end error(attribute_name, options) end # Creates a hint tag for the given attribute. Accepts a symbol indicating # an attribute for I18n lookup or a string. All the given options are sent # as :hint_html. # # == Examples # # f.hint :name # Do I18n lookup # f.hint :name, id: "cool_hint" # f.hint "Don't forget to accept this" # def hint(attribute_name, options = {}) options = options.dup options[:hint_html] = options.except(:hint_tag, :hint) if attribute_name.is_a?(String) options[:hint] = attribute_name attribute_name, column, input_type = nil, nil, nil else column = find_attribute_column(attribute_name) input_type = default_input_type(attribute_name, column, options) end wrapper.find(:hint). render(SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options)) end # Creates a default label tag for the given attribute. You can give a label # through the :label option or using i18n. All the given options are sent # as :label_html. # # == Examples # # f.label :name # Do I18n lookup # f.label :name, "Name" # Same behavior as Rails, do not add required tag # f.label :name, label: "Name" # Same as above, but adds required tag # # f.label :name, required: false # f.label :name, id: "cool_label" # def label(attribute_name, *args) return super if args.first.is_a?(String) || block_given? options = args.extract_options!.dup options[:label_html] = options.except(:label, :required, :as) column = find_attribute_column(attribute_name) input_type = default_input_type(attribute_name, column, options) SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options).label end # Creates an error notification message that only appears when the form object # has some error. You can give a specific message with the :message option, # otherwise it will look for a message using I18n. All other options given are # passed straight as html options to the html tag. # # == Examples # # f.error_notification # f.error_notification message: 'Something went wrong' # f.error_notification id: 'user_error_message', class: 'form_error' # def error_notification(options = {}) SimpleForm::ErrorNotification.new(self, options).render end # Create a collection of radio inputs for the attribute. Basically this # helper will create a radio input associated with a label for each # text/value option in the collection, using value_method and text_method # to convert these text/value. You can give a symbol or a proc to both # value_method and text_method, that will be evaluated for each item in # the collection. # # == Examples # # form_for @user do |f| # f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last # end # # # # # # # It is also possible to give a block that should generate the radio + # label. To wrap the radio with the label, for instance: # # form_for @user do |f| # f.collection_radio_buttons( # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last # ) do |b| # b.label { b.radio_button + b.text } # end # end # # == Options # # Collection radio accepts some extra options: # # * checked => the value that should be checked initially. # # * disabled => the value or values that should be disabled. Accepts a single # item or an array of items. # # * collection_wrapper_tag => the tag to wrap the entire collection. # # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag # # * item_wrapper_tag => the tag to wrap each item in the collection. # # * item_wrapper_class => the CSS class to use for item_wrapper_tag # # * a block => to generate the label + radio or any other component. def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block) SimpleForm::Tags::CollectionRadioButtons.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block) end # Creates a collection of check boxes for each item in the collection, # associated with a clickable label. Use value_method and text_method to # convert items in the collection for use as text/value in check boxes. # You can give a symbol or a proc to both value_method and text_method, # that will be evaluated for each item in the collection. # # == Examples # # form_for @user do |f| # f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last # end # # # # # # # # # It is also possible to give a block that should generate the check box + # label. To wrap the check box with the label, for instance: # # form_for @user do |f| # f.collection_check_boxes( # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last # ) do |b| # b.label { b.check_box + b.text } # end # end # # == Options # # Collection check box accepts some extra options: # # * checked => the value or values that should be checked initially. Accepts # a single item or an array of items. It overrides existing associations. # # * disabled => the value or values that should be disabled. Accepts a single # item or an array of items. # # * collection_wrapper_tag => the tag to wrap the entire collection. # # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option # is ignored if the :collection_wrapper_tag option is blank. # # * item_wrapper_tag => the tag to wrap each item in the collection. # # * item_wrapper_class => the CSS class to use for item_wrapper_tag # # * a block => to generate the label + check box or any other component. def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block) SimpleForm::Tags::CollectionCheckBoxes.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block) end # Extract the model names from the object_name mess, ignoring numeric and # explicit child indexes. # # Example: # # route[blocks_attributes][0][blocks_learning_object_attributes][1][foo_attributes] # ["route", "blocks", "blocks_learning_object", "foo"] # def lookup_model_names #:nodoc: @lookup_model_names ||= begin child_index = options[:child_index] names = object_name.to_s.scan(/(?!\d)\w+/).flatten names.delete(child_index) if child_index names.each { |name| name.gsub!('_attributes', '') } names.freeze end end # The action to be used in lookup. def lookup_action #:nodoc: @lookup_action ||= begin action = template.controller && template.controller.action_name return unless action action = action.to_s ACTIONS[action] || action end end private def fetch_association_collection(reflection, options) options.fetch(:collection) do relation = reflection.klass.all if reflection.respond_to?(:scope) && reflection.scope relation = reflection.klass.instance_exec(&reflection.scope) else order = reflection.options[:order] conditions = reflection.options[:conditions] conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call) relation = relation.where(conditions) relation = relation.order(order) if relation.respond_to?(:order) end relation end end def build_association_attribute(reflection, association, options) case reflection.macro when :belongs_to (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id" when :has_one raise ArgumentError, ":has_one associations are not supported by f.association" else if options[:as] == :select html_options = options[:input_html] ||= {} html_options[:multiple] = true unless html_options.key?(:multiple) end # Force the association to be preloaded for performance. if options[:preload] != false && object.respond_to?(association) target = object.send(association) target.to_a if target.respond_to?(:to_a) end :"#{reflection.name.to_s.singularize}_ids" end end # Find an input based on the attribute name. def find_input(attribute_name, options = {}, &block) column = find_attribute_column(attribute_name) input_type = default_input_type(attribute_name, column, options) if block_given? SimpleForm::Inputs::BlockInput.new(self, attribute_name, column, input_type, options, &block) else find_mapping(input_type).new(self, attribute_name, column, input_type, options) end end # Attempt to guess the better input type given the defined options. By # default alwayls fallback to the user :as option, or to a :select when a # collection is given. def default_input_type(attribute_name, column, options) return options[:as].to_sym if options[:as] custom_type = find_custom_type(attribute_name.to_s) and return custom_type return :select if options[:collection] input_type = column.try(:type) case input_type when :timestamp :datetime when :string, nil case attribute_name.to_s when /password/ then :password when /time_zone/ then :time_zone when /country/ then :country when /email/ then :email when /phone/ then :tel when /url/ then :url else file_method?(attribute_name) ? :file : (input_type || :string) end else input_type end end def find_custom_type(attribute_name) SimpleForm.input_mappings.find { |match, type| attribute_name =~ match }.try(:last) if SimpleForm.input_mappings end def file_method?(attribute_name) file = @object.send(attribute_name) if @object.respond_to?(attribute_name) file && SimpleForm.file_methods.any? { |m| file.respond_to?(m) } end def find_attribute_column(attribute_name) if @object.respond_to?(:column_for_attribute) && @object.has_attribute?(attribute_name) @object.column_for_attribute(attribute_name) end end def find_association_reflection(association) if @object.class.respond_to?(:reflect_on_association) @object.class.reflect_on_association(association) end end # Attempts to find a mapping. It follows the following rules: # # 1) It tries to find a registered mapping, if succeeds: # a) Try to find an alternative with the same name in the Object scope # b) Or use the found mapping # 2) If not, fallbacks to #{input_type}Input # 3) If not, fallbacks to SimpleForm::Inputs::#{input_type}Input def find_mapping(input_type) discovery_cache[input_type] ||= if mapping = self.class.mappings[input_type] mapping_override(mapping) || mapping else camelized = "#{input_type.to_s.camelize}Input" attempt_mapping_with_custom_namespace(camelized) || attempt_mapping(camelized, Object) || attempt_mapping(camelized, self.class) || raise("No input found for #{input_type}") end end # Attempts to find a wrapper mapping. It follows the following rules: # # 1) It tries to find a wrapper for the current form # 2) If not, it tries to find a config def find_wrapper_mapping(input_type) if options[:wrapper_mappings] && options[:wrapper_mappings][input_type] options[:wrapper_mappings][input_type] else SimpleForm.wrapper_mappings && SimpleForm.wrapper_mappings[input_type] end end def find_wrapper(input_type, options) if name = options[:wrapper] || find_wrapper_mapping(input_type) name.respond_to?(:render) ? name : SimpleForm.wrapper(name) else wrapper end end # If cache_discovery is enabled, use the class level cache that persists # between requests, otherwise use the instance one. def discovery_cache if SimpleForm.cache_discovery self.class.discovery_cache else @discovery_cache ||= {} end end def mapping_override(klass) name = klass.name if name =~ /^SimpleForm::Inputs/ input_name = name.split("::").last attempt_mapping_with_custom_namespace(input_name) || attempt_mapping(input_name, Object) end end def attempt_mapping(mapping, at) return if SimpleForm.inputs_discovery == false && at == Object begin at.const_get(mapping) rescue NameError => e raise if e.message !~ /#{mapping}$/ end end def attempt_mapping_with_custom_namespace(input_name) SimpleForm.custom_inputs_namespaces.each do |namespace| if (mapping = attempt_mapping(input_name, namespace.constantize)) return mapping end end nil end end end simple-form-3.2.0/lib/simple_form/helpers.rb0000644000175000017500000000106112623141213021222 0ustar terceiroterceiromodule SimpleForm # Helpers are made of several helpers that cannot be turned on automatically. # For instance, disabled cannot be turned on automatically, it requires the # user to explicitly pass the option disabled: true so it may work. module Helpers autoload :Autofocus, 'simple_form/helpers/autofocus' autoload :Disabled, 'simple_form/helpers/disabled' autoload :Readonly, 'simple_form/helpers/readonly' autoload :Required, 'simple_form/helpers/required' autoload :Validators, 'simple_form/helpers/validators' end end simple-form-3.2.0/lib/simple_form/wrappers.rb0000644000175000017500000000046212623141213021427 0ustar terceiroterceiromodule SimpleForm module Wrappers autoload :Builder, 'simple_form/wrappers/builder' autoload :Many, 'simple_form/wrappers/many' autoload :Root, 'simple_form/wrappers/root' autoload :Single, 'simple_form/wrappers/single' autoload :Leaf, 'simple_form/wrappers/leaf' end end simple-form-3.2.0/lib/simple_form/helpers/0000755000175000017500000000000012623141213020677 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/helpers/autofocus.rb0000644000175000017500000000024012623141213023230 0ustar terceiroterceiromodule SimpleForm module Helpers module Autofocus private def has_autofocus? options[:autofocus] == true end end end end simple-form-3.2.0/lib/simple_form/helpers/disabled.rb0000644000175000017500000000034412623141213022774 0ustar terceiroterceiromodule SimpleForm module Helpers module Disabled private def has_disabled? options[:disabled] == true end def disabled_class :disabled if has_disabled? end end end end simple-form-3.2.0/lib/simple_form/helpers/readonly.rb0000644000175000017500000000034412623141213023042 0ustar terceiroterceiromodule SimpleForm module Helpers module Readonly private def readonly_class :readonly if has_readonly? end def has_readonly? options[:readonly] == true end end end end simple-form-3.2.0/lib/simple_form/helpers/validators.rb0000644000175000017500000000211112623141213023367 0ustar terceiroterceiromodule SimpleForm module Helpers module Validators def has_validators? @has_validators ||= attribute_name && object.class.respond_to?(:validators_on) end private def attribute_validators object.class.validators_on(attribute_name) end def reflection_validators reflection ? object.class.validators_on(reflection.name) : [] end def valid_validator?(validator) !conditional_validators?(validator) && action_validator_match?(validator) end def conditional_validators?(validator) validator.options.include?(:if) || validator.options.include?(:unless) end def action_validator_match?(validator) return true if !validator.options.include?(:on) case validator.options[:on] when :save true when :create !object.persisted? when :update object.persisted? end end def find_validator(kind) attribute_validators.find { |v| v.kind == kind } if has_validators? end end end end simple-form-3.2.0/lib/simple_form/helpers/required.rb0000644000175000017500000000143512623141213023047 0ustar terceiroterceiromodule SimpleForm module Helpers module Required private def required_field? @required end def calculate_required if !options[:required].nil? options[:required] elsif has_validators? required_by_validators? else required_by_default? end end def required_by_validators? (attribute_validators + reflection_validators).any? { |v| v.kind == :presence && valid_validator?(v) } end def required_by_default? SimpleForm.required_by_default end # Do not use has_required? because we want to add the class # regardless of the required option. def required_class required_field? ? :required : :optional end end end end simple-form-3.2.0/lib/simple_form/map_type.rb0000644000175000017500000000067612623141213021411 0ustar terceiroterceirorequire 'active_support/core_ext/class/attribute' module SimpleForm module MapType def self.extended(base) base.class_attribute :mappings base.mappings = {} end def map_type(*types) map_to = types.extract_options![:to] raise ArgumentError, "You need to give :to as option to map_type" unless map_to self.mappings = mappings.merge types.each_with_object({}) { |t, m| m[t] = map_to } end end end simple-form-3.2.0/lib/simple_form/components/0000755000175000017500000000000012623141213021422 5ustar terceiroterceirosimple-form-3.2.0/lib/simple_form/components/errors.rb0000644000175000017500000000274012623141213023266 0ustar terceiroterceiromodule SimpleForm module Components module Errors def error(wrapper_options = nil) error_text if has_errors? end def full_error(wrapper_options = nil) full_error_text if options[:error] != false && has_errors? end def has_errors? object && object.respond_to?(:errors) && errors.present? end protected def error_text text = has_custom_error? ? options[:error] : errors.send(error_method) "#{html_escape(options[:error_prefix])} #{html_escape(text)}".lstrip.html_safe end def full_error_text has_custom_error? ? options[:error] : full_errors.send(error_method) end def error_method options[:error_method] || SimpleForm.error_method end def errors @errors ||= (errors_on_attribute + errors_on_association).compact end def full_errors @full_errors ||= (full_errors_on_attribute + full_errors_on_association).compact end def errors_on_attribute object.errors[attribute_name] end def full_errors_on_attribute object.errors.full_messages_for(attribute_name) end def errors_on_association reflection ? object.errors[reflection.name] : [] end def full_errors_on_association reflection ? object.errors.full_messages_for(reflection.name) : [] end def has_custom_error? options[:error].is_a?(String) end end end end simple-form-3.2.0/lib/simple_form/components/hints.rb0000644000175000017500000000100512623141213023070 0ustar terceiroterceiromodule SimpleForm module Components # Needs to be enabled in order to do automatic lookups. module Hints def hint(wrapper_options = nil) @hint ||= begin hint = options[:hint] if hint.is_a?(String) html_escape(hint) else content = translate_from_namespace(:hints) content.html_safe if content end end end def has_hint? options[:hint] != false && hint.present? end end end end simple-form-3.2.0/lib/simple_form/components/pattern.rb0000644000175000017500000000145312623141213023427 0ustar terceiroterceiromodule SimpleForm module Components # Needs to be enabled in order to do automatic lookups. module Pattern def pattern(wrapper_options = nil) input_html_options[:pattern] ||= pattern_source nil end private def pattern_source pattern = options[:pattern] if pattern.is_a?(String) pattern elsif (pattern_validator = find_pattern_validator) && (with = pattern_validator.options[:with]) evaluate_format_validator_option(with).source end end def find_pattern_validator find_validator(:format) end def evaluate_format_validator_option(option) if option.respond_to?(:call) option.call(object) else option end end end end end simple-form-3.2.0/lib/simple_form/components/placeholders.rb0000644000175000017500000000067112623141213024420 0ustar terceiroterceiromodule SimpleForm module Components # Needs to be enabled in order to do automatic lookups. module Placeholders def placeholder(wrapper_options = nil) input_html_options[:placeholder] ||= placeholder_text nil end def placeholder_text placeholder = options[:placeholder] placeholder.is_a?(String) ? placeholder : translate_from_namespace(:placeholders) end end end end simple-form-3.2.0/lib/simple_form/components/html5.rb0000644000175000017500000000116412623141213023002 0ustar terceiroterceiromodule SimpleForm module Components module HTML5 def initialize(*) @html5 = false end def html5(wrapper_options = nil) @html5 = true input_html_options[:required] = has_required? input_html_options[:'aria-required'] = has_required? || nil nil end def html5? @html5 end def has_required? # We need to check browser_validations because # some browsers are still checking required even # if novalidate was given. required_field? && SimpleForm.browser_validations end end end end simple-form-3.2.0/lib/simple_form/components/labels.rb0000644000175000017500000000473012623141213023215 0ustar terceiroterceiromodule SimpleForm module Components module Labels extend ActiveSupport::Concern module ClassMethods #:nodoc: def translate_required_html i18n_cache :translate_required_html do I18n.t(:"simple_form.required.html", default: %[#{translate_required_mark}] ) end end def translate_required_text I18n.t(:"simple_form.required.text", default: 'required') end def translate_required_mark I18n.t(:"simple_form.required.mark", default: '*') end end def label(wrapper_options = nil) label_options = merge_wrapper_options(label_html_options, wrapper_options) if generate_label_for_attribute? @builder.label(label_target, label_text, label_options) else template.label_tag(nil, label_text, label_options) end end def label_text(wrapper_options = nil) label_text = options[:label_text] || SimpleForm.label_text label_text.call(html_escape(raw_label_text), required_label_text, options[:label].present?).strip.html_safe end def label_target attribute_name end def label_html_options label_html_classes = SimpleForm.additional_classes_for(:label) { [input_type, required_class, disabled_class, SimpleForm.label_class].compact } label_options = html_options_for(:label, label_html_classes) if options.key?(:input_html) && options[:input_html].key?(:id) label_options[:for] = options[:input_html][:id] end label_options end protected def raw_label_text #:nodoc: options[:label] || label_translation end # Default required text when attribute is required. def required_label_text #:nodoc: required_field? ? self.class.translate_required_html.dup : '' end # First check labels translation and then human attribute name. def label_translation #:nodoc: if SimpleForm.translate_labels && (translated_label = translate_from_namespace(:labels)) translated_label elsif object.class.respond_to?(:human_attribute_name) object.class.human_attribute_name(reflection_or_attribute_name.to_s) else attribute_name.to_s.humanize end end def generate_label_for_attribute? true end end end end simple-form-3.2.0/lib/simple_form/components/readonly.rb0000644000175000017500000000107212623141213023564 0ustar terceiroterceiromodule SimpleForm module Components # Needs to be enabled in order to do automatic lookups. module Readonly def readonly(wrapper_options = nil) if readonly_attribute? && !has_readonly? input_html_options[:readonly] ||= true input_html_classes << :readonly end nil end private def readonly_attribute? object.class.respond_to?(:readonly_attributes) && object.persisted? && object.class.readonly_attributes.include?(attribute_name.to_s) end end end end simple-form-3.2.0/lib/simple_form/components/min_max.rb0000644000175000017500000000267712623141213023413 0ustar terceiroterceiromodule SimpleForm module Components module MinMax def min_max(wrapper_options = nil) if numeric_validator = find_numericality_validator validator_options = numeric_validator.options input_html_options[:min] ||= minimum_value(validator_options) input_html_options[:max] ||= maximum_value(validator_options) end nil end private def integer? input_type == :integer end def minimum_value(validator_options) if integer? && validator_options.key?(:greater_than) evaluate_numericality_validator_option(validator_options[:greater_than]) + 1 else evaluate_numericality_validator_option(validator_options[:greater_than_or_equal_to]) end end def maximum_value(validator_options) if integer? && validator_options.key?(:less_than) evaluate_numericality_validator_option(validator_options[:less_than]) - 1 else evaluate_numericality_validator_option(validator_options[:less_than_or_equal_to]) end end def find_numericality_validator find_validator(:numericality) end def evaluate_numericality_validator_option(option) if option.is_a?(Numeric) option elsif option.is_a?(Symbol) object.send(option) elsif option.respond_to?(:call) option.call(object) end end end end end simple-form-3.2.0/lib/simple_form/components/label_input.rb0000644000175000017500000000145312623141213024250 0ustar terceiroterceiromodule SimpleForm module Components module LabelInput extend ActiveSupport::Concern included do include SimpleForm::Components::Labels end def label_input(wrapper_options = nil) if options[:label] == false deprecated_component(:input, wrapper_options) else deprecated_component(:label, wrapper_options) + deprecated_component(:input, wrapper_options) end end private def deprecated_component(namespace, wrapper_options) method = method(namespace) if method.arity == 0 ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: namespace }) method.call else method.call(wrapper_options) end end end end end simple-form-3.2.0/lib/simple_form/components/maxlength.rb0000644000175000017500000000156712623141213023747 0ustar terceiroterceiromodule SimpleForm module Components # Needs to be enabled in order to do automatic lookups. module Maxlength def maxlength(wrapper_options = nil) input_html_options[:maxlength] ||= maximum_length_from_validation || limit nil end private def maximum_length_from_validation maxlength = options[:maxlength] if maxlength.is_a?(String) || maxlength.is_a?(Integer) maxlength else length_validator = find_length_validator if length_validator && !has_tokenizer?(length_validator) length_validator.options[:is] || length_validator.options[:maximum] end end end def find_length_validator find_validator(:length) end def has_tokenizer?(length_validator) length_validator.options[:tokenizer] end end end end simple-form-3.2.0/lib/simple_form/components.rb0000644000175000017500000000133012623141213021744 0ustar terceiroterceiromodule SimpleForm # Components are a special type of helpers that can work on their own. # For example, by using a component, it will automatically change the # output under given circumstances without user input. For example, # the disabled helper always need a disabled: true option given # to the input in order to be enabled. On the other hand, things like # hints can generate output automatically by doing I18n lookups. module Components extend ActiveSupport::Autoload autoload :Errors autoload :Hints autoload :HTML5 autoload :LabelInput autoload :Labels autoload :MinMax autoload :Maxlength autoload :Pattern autoload :Placeholders autoload :Readonly end end simple-form-3.2.0/lib/simple_form/tags.rb0000644000175000017500000000422312623141213020521 0ustar terceiroterceiromodule SimpleForm module Tags module CollectionExtensions private def render_collection item_wrapper_tag = @options.fetch(:item_wrapper_tag, :span) item_wrapper_class = @options[:item_wrapper_class] @collection.map do |item| value = value_for_collection(item, @value_method) text = value_for_collection(item, @text_method) default_html_options = default_html_options_for_collection(item, value) additional_html_options = option_html_attributes(item) rendered_item = yield item, value, text, default_html_options.merge(additional_html_options) if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested label_options = default_html_options.slice(:index, :namespace) label_options['class'] = @options[:item_label_class] rendered_item = @template_object.label(@object_name, sanitize_attribute_name(value), rendered_item, label_options) end item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item end.join.html_safe end def wrap_rendered_collection(collection) wrapper_tag = @options[:collection_wrapper_tag] if wrapper_tag wrapper_class = @options[:collection_wrapper_class] @template_object.content_tag(wrapper_tag, collection, class: wrapper_class) else collection end end end class CollectionRadioButtons < ActionView::Helpers::Tags::CollectionRadioButtons include CollectionExtensions def render wrap_rendered_collection(super) end private def render_component(builder) builder.radio_button + builder.label(class: "collection_radio_buttons") end end class CollectionCheckBoxes < ActionView::Helpers::Tags::CollectionCheckBoxes include CollectionExtensions def render wrap_rendered_collection(super) end private def render_component(builder) builder.check_box + builder.label(class: "collection_check_boxes") end end end end simple-form-3.2.0/lib/simple_form/i18n_cache.rb0000644000175000017500000000106712623141213021470 0ustar terceiroterceiromodule SimpleForm # A lot of configuration values are retrived from I18n, # like boolean collection, required string. This module provides # caching facility to speed up form construction. module I18nCache def i18n_cache(key) get_i18n_cache(key)[I18n.locale] ||= yield.freeze end def get_i18n_cache(key) if class_variable_defined?(:"@@#{key}") class_variable_get(:"@@#{key}") else reset_i18n_cache(key) end end def reset_i18n_cache(key) class_variable_set(:"@@#{key}", {}) end end end simple-form-3.2.0/CHANGELOG.md0000644000175000017500000001235712623141213015774 0ustar terceiroterceiro## 3.2.0 ### bug fix * Improve performance of input generation by disabling support for `_html` translations. This reverts the feature introduced on the 3.1.0 branch ## 3.1.1 ### enhancements * Add the `disabled_class` to the label when the input is disabled. [@rhodrid](https://github.com/rhodrid) ### bug fix * Make it possible to override `required` value that was previously set in the wrapper. [@nashby](https://github.com/nashby) * `date/time/datetime` inputs now correctly generate the label `for` attribute when HTML5 compatibility is explicitly enabled. [@ericsullivan](https://github.com/ericsullivan) * The datetime, date, and time inputs now have a nice format by default on bootstrap. [@ulissesalmeida](https://github.com/ulissesalmeida) [@eltonchrls](https://github.com/eltonchrls) * Now it is possible to set custom input mappings for collections. Example: ```ruby # On configuration: config.input_mappings = { /gender$/ => :check_boxes } # On form: f.input :gender, collection: [:male, :female] ``` [strangeworks](https://github.com/strangeworks) ## 3.1.0 ### enhancements * Update foundation generator to version 5. [@jorge-d](https://github.com/jorge-d) * Add mapping to `uuid` columns. * Add custom namespaces for custom inputs feature. [@vala](https://github.com/vala) * Add `:unless_blank` option to the wrapper API. [@IanVaughan](https://github.com/IanVaughan) * Add support to html markup in the I18n options. [@laurocaetano](https://github.com/laurocaetano) * Add the `full_error` component. [@laurocaetano](https://github.com/laurocaetano) * Add support to `scope` to be used on associations. [@laurocaetano](https://github.com/laurocaetano) * Execute the association `condition` in the object context. [@laurocaetano](https://github.com/laurocaetano) * Check if the given association responds to `order` before calling it. [@laurocaetano](https://github.com/laurocaetano) * Add Bootstrap 3 initializer template. * For radio or checkbox collection always use `:item_wrapper_tag` to wrap the content and add `label` when using `boolean_style` with `:nested` [@kassio](https://github.com/kassio) and [@erichkist](https://github.com/erichkist) * `input_field` uses the same wrapper as input but only with attribute components. [@nashby](https://github.com/nashby) * Add wrapper mapping per form basis [@rcillo](https://github.com/rcillo) and [@bernardoamc](https://github.com/bernardoamc) * Add `for` attribute to `label` when collections are rendered as radio or checkbox [@erichkist](https://github.com/erichkist), [@ulissesalmeida](https://github.com/ulissesalmeida) and [@fabioyamate](https://github.com/fabioyamate) * Add `include_default_input_wrapper_class` config [@luizcosta](https://github.com/luizcosta) * Map `datetime`, `date` and `time` input types to their respective HTML5 input tags when the `:html5` is set to `true` [@volmer](https://github.com/volmer) * Add `boolean_label_class` config. * Add `:html` option to include additional attributes on custom wrappers [@remofritzsche](https://github.com/remofritzsche) and [@ulissesalmeida](https://github.com/ulissesalmeida) * Make possible to use the Wrappers API to define attributes for the components. See https://github.com/plataformatec/simple_form/pull/997 for more information. * Put a whitespace before the `inline_label` options of boolean input if it is present. * Add support to configure the `label_text` proc at the wrapper level. [@NOX73](https://github.com/NOX73) * `label_text` proc now receive three arguments (label, request, and if the label was explicit). [@timscott](https://github.com/timscott) * Add I18n support to `:include_blank` and `:prompt` when `:translate` is used as value. [@haines](https://github.com/plataformatec/simple_form/pull/616) * Add support to define custom error messages for the attributes. * Add support to change the I18n scope to be used in Simple Form. [@nielsbuus](https://github.com/nielsbuus) * The default form class can now be overridden with `html: { :class }`. [@rmm5t](https://github.com/rmm5t) ### bug fix * Fix `full_error` when the attribute is an association. [@mvdamme](https://github.com/jorge-d) * Fix suppport to `:namespace` and `:index` options for nested check boxes and radio buttons when the attribute is an association. * Collection input that uses automatic collection translation properly sets checked values. Closes [#971](https://github.com/plataformatec/simple_form/issues/971) [@nashby](https://github.com/nashby) * Collection input generates `required` attribute if it has `prompt` option. [@nashby](https://github.com/nashby) * Grouped collection uses the first non-empty object to detect label and value methods. ## deprecation * Methods on custom inputs now accept a required argument with the wrapper options. See https://github.com/plataformatec/simple_form/pull/997 for more information. * SimpleForm.form_class is deprecated in favor of SimpleForm.default_form_class. Future versions of Simple Form will not generate `simple_form` class for the form element. See https://github.com/plataformatec/simple_form/pull/1109 for more information. Please check [v3.0](https://github.com/plataformatec/simple_form/blob/v3.0/CHANGELOG.md) for previous changes. simple-form-3.2.0/README.md0000644000175000017500000010711112623141213015433 0ustar terceiroterceiro![Simple Form Logo](https://raw.github.com/plataformatec/simple_form/master/simple_form.png) By [Plataformatec](http://plataformatec.com.br/). Rails forms made easy. **Simple Form** aims to be as flexible as possible while helping you with powerful components to create your forms. The basic goal of **Simple Form** is to not touch your way of defining the layout, letting you find the better design for your eyes. Most of the DSL was inherited from Formtastic, which we are thankful for and should make you feel right at home. INFO: This README is [also available in a friendly navigable format](http://simple-form.plataformatec.com.br/) and refers to **Simple Form** 3.1. For older releases, check the related branch for your version. ## Installation Add it to your Gemfile: ```ruby gem 'simple_form' ``` Run the following command to install it: ```console bundle install ``` Run the generator: ```console rails generate simple_form:install ``` ### Bootstrap **Simple Form** can be easily integrated to the [Bootstrap](http://getbootstrap.com/). To do that you have to use the `bootstrap` option in the install generator, like this: ```console rails generate simple_form:install --bootstrap ``` You have to be sure that you added a copy of the [Bootstrap](http://getbootstrap.com/) assets on your application. For more information see the generator output, our [example application code](https://github.com/rafaelfranca/simple_form-bootstrap) and [the live example app](http://simple-form-bootstrap.plataformatec.com.br/). ### Zurb Foundation 5 To generate wrappers that are compatible with [Zurb Foundation 5](http://foundation.zurb.com/), pass the `foundation` option to the generator, like this: ```console rails generate simple_form:install --foundation ``` Please note that the Foundation wrapper does not support the `:hint` option by default. In order to enable hints, please uncomment the appropriate line in `config/initializers/simple_form_foundation.rb`. You will need to provide your own CSS styles for hints. Please see the [instructions on how to install Foundation in a Rails app](http://foundation.zurb.com/docs/applications.html). ### Country Select If you want to use the country select, you will need the [country_select gem](https://rubygems.org/gems/country_select), add it to your Gemfile: ```ruby gem 'country_select' ``` If you don't want to use the gem you can easily override this behaviour by mapping the country inputs to something else, with a line like this in your `simple_form.rb` initializer: ```ruby config.input_mappings = { /country/ => :string } ``` ## Usage **Simple Form** was designed to be customized as you need to. Basically it's a stack of components that are invoked to create a complete html input for you, which by default contains label, hints, errors and the input itself. It does not aim to create a lot of different logic from the default Rails form helpers, as they do a great job by themselves. Instead, **Simple Form** acts as a DSL and just maps your input type (retrieved from the column definition in the database) to a specific helper method. To start using **Simple Form** you just have to use the helper it provides: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username %> <%= f.input :password %> <%= f.button :submit %> <% end %> ``` This will generate an entire form with labels for user name and password as well, and render errors by default when you render the form with invalid data (after submitting for example). You can overwrite the default label by passing it to the input method. You can also add a hint, an error, or even a placeholder. For boolean inputs, you can add an inline label as well: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username, label: 'Your username please', error: 'Username is mandatory, please specify one' %> <%= f.input :password, hint: 'No special characters.' %> <%= f.input :email, placeholder: 'user@domain.com' %> <%= f.input :remember_me, inline_label: 'Yes, remember me' %> <%= f.button :submit %> <% end %> ``` In some cases you may want to disable labels, hints or error. Or you may want to configure the html of any of them: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username, label_html: { class: 'my_class' } %> <%= f.input :password, hint: false, error_html: { id: 'password_error'} %> <%= f.input :password_confirmation, label: false %> <%= f.button :submit %> <% end %> ``` It is also possible to pass any html attribute straight to the input, by using the `:input_html` option, for instance: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username, input_html: { class: 'special' } %> <%= f.input :password, input_html: { maxlength: 20 } %> <%= f.input :remember_me, input_html: { value: '1' } %> <%= f.button :submit %> <% end %> ``` If you want to pass the same options to all inputs in the form (for example, a default class), you can use the `:defaults` option in `simple_form_for`. Specific options in `input` call will overwrite the defaults: ```erb <%= simple_form_for @user, defaults: { input_html: { class: 'default_class' } } do |f| %> <%= f.input :username, input_html: { class: 'special' } %> <%= f.input :password, input_html: { maxlength: 20 } %> <%= f.input :remember_me, input_html: { value: '1' } %> <%= f.button :submit %> <% end %> ``` Since **Simple Form** generates a wrapper div around your label and input by default, you can pass any html attribute to that wrapper as well using the `:wrapper_html` option, like so: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username, wrapper_html: { class: 'username' } %> <%= f.input :password, wrapper_html: { id: 'password' } %> <%= f.input :remember_me, wrapper_html: { class: 'options' } %> <%= f.button :submit %> <% end %> ``` Required fields are marked with an * prepended to their labels. By default all inputs are required. When the form object has `presence` validations attached to its fields, **Simple Form** tells required and optional fields apart. For performance reasons, this detection is skipped on validations that make use of conditional options, such as `:if` and `:unless`. And of course, the `required` property of any input can be overwritten as needed: ```erb <%= simple_form_for @user do |f| %> <%= f.input :name, required: false %> <%= f.input :username %> <%= f.input :password %> <%= f.button :submit %> <% end %> ``` By default, **Simple Form** will look at the column type in the database and use an appropriate input for the column. For example, a column created with type `:text` in the database will use a `textarea` input by default. See the section [Available input types and defaults for each column type](https://github.com/plataformatec/simple_form#available-input-types-and-defaults-for-each-column-type) for a complete list of defaults. **Simple Form** also lets you overwrite the default input type it creates: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username %> <%= f.input :password %> <%= f.input :description, as: :text %> <%= f.input :accepts, as: :radio_buttons %> <%= f.button :submit %> <% end %> ``` So instead of a checkbox for the *accepts* attribute, you'll have a pair of radio buttons with yes/no labels and a textarea instead of a text field for the description. You can also render boolean attributes using `as: :select` to show a dropdown. It is also possible to give the `:disabled` option to **Simple Form**, and it'll automatically mark the wrapper as disabled with a CSS class, so you can style labels, hints and other components inside the wrapper as well: ```erb <%= simple_form_for @user do |f| %> <%= f.input :username, disabled: true, hint: 'You cannot change your username.' %> <%= f.button :submit %> <% end %> ``` **Simple Form** accepts same options as their corresponding input type helper in Rails: ```erb <%= simple_form_for @user do |f| %> <%= f.input :date_of_birth, as: :date, start_year: Date.today.year - 90, end_year: Date.today.year - 12, discard_day: true, order: [:month, :year] %> <%= f.input :accepts, as: :boolean, checked_value: true, unchecked_value: false %> <%= f.button :submit %> <% end %> ``` **Simple Form** also allows you to use label, hint, input_field, error and full_error helpers (please take a look at the rdocs for each method for more info): ```erb <%= simple_form_for @user do |f| %> <%= f.label :username %> <%= f.input_field :username %> <%= f.hint 'No special characters, please!' %> <%= f.error :username, id: 'user_name_error' %> <%= f.full_error :token %> <%= f.submit 'Save' %> <% end %> ``` Any extra option passed to these methods will be rendered as html option. ### Stripping away all wrapper divs **Simple Form** also allows you to strip away all the div wrappers around the `` field that is generated with the usual `f.input`. The easiest way to achieve this is to use `f.input_field`. Example: ```ruby simple_form_for @user do |f| f.input_field :name f.input_field :remember_me, as: :boolean end ``` ```html
...
``` For check boxes and radio buttons you can remove the label changing `boolean_style` from default value `:nested` to `:inline`. Example: ```ruby simple_form_for @user do |f| f.input_field :name f.input_field :remember_me, as: :boolean, boolean_style: :inline end ``` ```html
...
``` Produces: ```html ``` To view the actual RDocs for this, check them out here - http://rubydoc.info/github/plataformatec/simple_form/master/SimpleForm/FormBuilder:input_field ### Collections And what if you want to create a select containing the age from 18 to 60 in your form? You can do it overriding the `:collection` option: ```erb <%= simple_form_for @user do |f| %> <%= f.input :user %> <%= f.input :age, collection: 18..60 %> <%= f.button :submit %> <% end %> ``` Collections can be arrays or ranges, and when a `:collection` is given the `:select` input will be rendered by default, so we don't need to pass the `as: :select` option. Other types of collection are `:radio_buttons` and `:check_boxes`. Those are added by **Simple Form** to Rails set of form helpers (read Extra Helpers section below for more information). Collection inputs accept two other options beside collections: * *label_method* => the label method to be applied to the collection to retrieve the label (use this instead of the `text_method` option in `collection_select`) * *value_method* => the value method to be applied to the collection to retrieve the value Those methods are useful to manipulate the given collection. Both of these options also accept lambda/procs in case you want to calculate the value or label in a special way eg. custom translation. All other options given are sent straight to the underlying helper. For example, you can give prompt as: ```ruby f.input :age, collection: 18..60, prompt: "Select your age", selected: 21 ``` Extra options are passed into helper [`collection_select`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select). It is also possible to create grouped collection selects, that will use the html *optgroup* tags, like this: ```ruby f.input :country_id, collection: @continents, as: :grouped_select, group_method: :countries ``` Grouped collection inputs accept the same `:label_method` and `:value_method` options, which will be used to retrieve label/value attributes for the `option` tags. Besides that, you can give: * *group_method* => the method to be called on the given collection to generate the options for each group (required) * *group_label_method* => the label method to be applied on the given collection to retrieve the label for the _optgroup_ (**Simple Form** will attempt to guess the best one the same way it does with `:label_method`) ### Priority **Simple Form** also supports `:time_zone` and `:country`. When using such helpers, you can give `:priority` as an option to select which time zones and/or countries should be given higher priority: ```ruby f.input :residence_country, priority: [ "Brazil" ] f.input :time_zone, priority: /US/ ``` Those values can also be configured with a default value to be used on the site through the `SimpleForm.country_priority` and `SimpleForm.time_zone_priority` helpers. Note: While using `country_select` if you want to restrict to only a subset of countries for a specific drop down then you may use the `:collection` option: ```ruby f.input :shipping_country, priority: [ "Brazil" ], collection: [ "Australia", "Brazil", "New Zealand"] ``` ### Associations To deal with associations, **Simple Form** can generate select inputs, a series of radios buttons or checkboxes. Lets see how it works: imagine you have a user model that belongs to a company and `has_and_belongs_to_many` roles. The structure would be something like: ```ruby class User < ActiveRecord::Base belongs_to :company has_and_belongs_to_many :roles end class Company < ActiveRecord::Base has_many :users end class Role < ActiveRecord::Base has_and_belongs_to_many :users end ``` Now we have the user form: ```erb <%= simple_form_for @user do |f| %> <%= f.input :name %> <%= f.association :company %> <%= f.association :roles %> <%= f.button :submit %> <% end %> ``` Simple enough, right? This is going to render a `:select` input for choosing the `:company`, and another `:select` input with `:multiple` option for the `:roles`. You can, of course, change it to use radio buttons and checkboxes as well: ```ruby f.association :company, as: :radio_buttons f.association :roles, as: :check_boxes ``` The association helper just invokes `input` under the hood, so all options available to `:select`, `:radio_buttons` and `:check_boxes` are also available to association. Additionally, you can specify the collection by hand, all together with the prompt: ```ruby f.association :company, collection: Company.active.order(:name), prompt: "Choose a Company" ``` In case you want to declare different labels and values: ```ruby f.association :company, label_method: :company_name, value_method: :id, include_blank: false ``` Please note that the association helper is currently only tested with Active Record. It currently does not work well with Mongoid and depending on the ORM you're using your mileage may vary. ### Buttons All web forms need buttons, right? **Simple Form** wraps them in the DSL, acting like a proxy: ```erb <%= simple_form_for @user do |f| %> <%= f.input :name %> <%= f.button :submit %> <% end %> ``` The above will simply call submit. You choose to use it or not, it's just a question of taste. The button method also accepts optional parameters, that are delegated to the underlying submit call: ```erb <%= f.button :submit, "Custom Button Text", class: "my-button" %> ``` To create a `