simple_form 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of simple_form might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -32
- data/README.md +161 -119
- data/lib/generators/simple_form/install_generator.rb +3 -3
- data/lib/generators/simple_form/templates/README +1 -1
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +16 -13
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +14 -14
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +3 -3
- data/lib/simple_form/action_view_extensions/builder.rb +1 -319
- data/lib/simple_form/action_view_extensions/form_helper.rb +2 -9
- data/lib/simple_form/components/html5.rb +5 -2
- data/lib/simple_form/components/labels.rb +3 -3
- data/lib/simple_form/components/maxlength.rb +1 -8
- data/lib/simple_form/components/pattern.rb +2 -2
- data/lib/simple_form/components.rb +1 -1
- data/lib/simple_form/error_notification.rb +2 -2
- data/lib/simple_form/form_builder.rb +155 -51
- data/lib/simple_form/helpers.rb +1 -1
- data/lib/simple_form/inputs/base.rb +6 -6
- data/lib/simple_form/inputs/block_input.rb +1 -1
- data/lib/simple_form/inputs/boolean_input.rb +6 -4
- data/lib/simple_form/inputs/collection_input.rb +6 -6
- data/lib/simple_form/inputs/date_time_input.rb +1 -1
- data/lib/simple_form/inputs/numeric_input.rb +0 -6
- data/lib/simple_form/inputs/password_input.rb +0 -1
- data/lib/simple_form/inputs/string_input.rb +0 -1
- data/lib/simple_form/railtie.rb +7 -0
- data/lib/simple_form/tags.rb +62 -0
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form/wrappers/builder.rb +5 -29
- data/lib/simple_form/wrappers/many.rb +1 -1
- data/lib/simple_form/wrappers/root.rb +1 -1
- data/lib/simple_form/wrappers.rb +1 -1
- data/lib/simple_form.rb +43 -47
- data/test/action_view_extensions/builder_test.rb +78 -92
- data/test/action_view_extensions/form_helper_test.rb +25 -16
- data/test/components/label_test.rb +46 -46
- data/test/form_builder/association_test.rb +47 -29
- data/test/form_builder/button_test.rb +4 -4
- data/test/form_builder/error_notification_test.rb +8 -8
- data/test/form_builder/error_test.rb +12 -12
- data/test/form_builder/general_test.rb +71 -52
- data/test/form_builder/hint_test.rb +22 -22
- data/test/form_builder/input_field_test.rb +29 -12
- data/test/form_builder/label_test.rb +7 -7
- data/test/form_builder/wrapper_test.rb +21 -21
- data/test/inputs/boolean_input_test.rb +35 -23
- data/test/inputs/collection_check_boxes_input_test.rb +66 -55
- data/test/inputs/collection_radio_buttons_input_test.rb +81 -79
- data/test/inputs/collection_select_input_test.rb +76 -45
- data/test/inputs/datetime_input_test.rb +17 -11
- data/test/inputs/disabled_test.rb +10 -10
- data/test/inputs/discovery_test.rb +4 -4
- data/test/inputs/file_input_test.rb +1 -1
- data/test/inputs/general_test.rb +28 -12
- data/test/inputs/grouped_collection_select_input_test.rb +33 -20
- data/test/inputs/hidden_input_test.rb +3 -2
- data/test/inputs/numeric_input_test.rb +3 -3
- data/test/inputs/priority_input_test.rb +9 -3
- data/test/inputs/readonly_test.rb +12 -12
- data/test/inputs/required_test.rb +5 -5
- data/test/inputs/string_input_test.rb +15 -25
- data/test/inputs/text_input_test.rb +1 -1
- data/test/support/misc_helpers.rb +46 -24
- data/test/support/mock_controller.rb +6 -6
- data/test/support/models.rb +80 -62
- data/test/test_helper.rb +17 -34
- metadata +31 -29
- data/lib/simple_form/core_ext/hash.rb +0 -16
| @@ -1,5 +1,6 @@ | |
| 1 | 
            -
            require ' | 
| 1 | 
            +
            require 'active_support/core_ext/object/deep_dup'
         | 
| 2 2 | 
             
            require 'simple_form/map_type'
         | 
| 3 | 
            +
            require 'simple_form/tags'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module SimpleForm
         | 
| 5 6 | 
             
              class FormBuilder < ActionView::Helpers::FormBuilder
         | 
| @@ -7,26 +8,28 @@ module SimpleForm | |
| 7 8 |  | 
| 8 9 | 
             
                # When action is create or update, we still should use new and edit
         | 
| 9 10 | 
             
                ACTIONS = {
         | 
| 10 | 
            -
                  : | 
| 11 | 
            -
                  : | 
| 11 | 
            +
                  create: :new,
         | 
| 12 | 
            +
                  update: :edit
         | 
| 12 13 | 
             
                }
         | 
| 13 14 |  | 
| 15 | 
            +
                ATTRIBUTE_COMPONENTS = [:html5, :min_max, :maxlength, :placeholder, :pattern, :readonly]
         | 
| 16 | 
            +
             | 
| 14 17 | 
             
                extend MapType
         | 
| 15 18 | 
             
                include SimpleForm::Inputs
         | 
| 16 19 |  | 
| 17 | 
            -
                map_type :text,                                : | 
| 18 | 
            -
                map_type :file,                                : | 
| 19 | 
            -
                map_type :string, :email, :search, :tel, :url, : | 
| 20 | 
            -
                map_type :password,                            : | 
| 21 | 
            -
                map_type :integer, :decimal, :float,           : | 
| 22 | 
            -
                map_type :range,                               : | 
| 23 | 
            -
                map_type :check_boxes,                         : | 
| 24 | 
            -
                map_type :radio_buttons,                       : | 
| 25 | 
            -
                map_type :select,                              : | 
| 26 | 
            -
                map_type :grouped_select,                      : | 
| 27 | 
            -
                map_type :date, :time, :datetime,              : | 
| 28 | 
            -
                map_type :country, :time_zone,                 : | 
| 29 | 
            -
                map_type :boolean,                             : | 
| 20 | 
            +
                map_type :text,                                to: SimpleForm::Inputs::TextInput
         | 
| 21 | 
            +
                map_type :file,                                to: SimpleForm::Inputs::FileInput
         | 
| 22 | 
            +
                map_type :string, :email, :search, :tel, :url, to: SimpleForm::Inputs::StringInput
         | 
| 23 | 
            +
                map_type :password,                            to: SimpleForm::Inputs::PasswordInput
         | 
| 24 | 
            +
                map_type :integer, :decimal, :float,           to: SimpleForm::Inputs::NumericInput
         | 
| 25 | 
            +
                map_type :range,                               to: SimpleForm::Inputs::RangeInput
         | 
| 26 | 
            +
                map_type :check_boxes,                         to: SimpleForm::Inputs::CollectionCheckBoxesInput
         | 
| 27 | 
            +
                map_type :radio_buttons,                       to: SimpleForm::Inputs::CollectionRadioButtonsInput
         | 
| 28 | 
            +
                map_type :select,                              to: SimpleForm::Inputs::CollectionSelectInput
         | 
| 29 | 
            +
                map_type :grouped_select,                      to: SimpleForm::Inputs::GroupedCollectionSelectInput
         | 
| 30 | 
            +
                map_type :date, :time, :datetime,              to: SimpleForm::Inputs::DateTimeInput
         | 
| 31 | 
            +
                map_type :country, :time_zone,                 to: SimpleForm::Inputs::PriorityInput
         | 
| 32 | 
            +
                map_type :boolean,                             to: SimpleForm::Inputs::BooleanInput
         | 
| 30 33 |  | 
| 31 34 | 
             
                def self.discovery_cache
         | 
| 32 35 | 
             
                  @discovery_cache ||= {}
         | 
| @@ -48,7 +51,7 @@ module SimpleForm | |
| 48 51 | 
             
                #
         | 
| 49 52 | 
             
                #   # Imagine @user has error "can't be blank" on name
         | 
| 50 53 | 
             
                #   simple_form_for @user do |f|
         | 
| 51 | 
            -
                #     f.input :name, : | 
| 54 | 
            +
                #     f.input :name, hint: 'My hint'
         | 
| 52 55 | 
             
                #   end
         | 
| 53 56 | 
             
                #
         | 
| 54 57 | 
             
                # This is the output html (only the input portion, not the form):
         | 
| @@ -57,7 +60,7 @@ module SimpleForm | |
| 57 60 | 
             
                #       <abbr title="required">*</abbr> Super User Name!
         | 
| 58 61 | 
             
                #     </label>
         | 
| 59 62 | 
             
                #     <input class="string required" id="user_name" maxlength="100"
         | 
| 60 | 
            -
                #        name="user[name]"  | 
| 63 | 
            +
                #        name="user[name]" type="text" value="Carlos" />
         | 
| 61 64 | 
             
                #     <span class="hint">My hint</span>
         | 
| 62 65 | 
             
                #     <span class="error">can't be blank</span>
         | 
| 63 66 | 
             
                #
         | 
| @@ -66,15 +69,15 @@ module SimpleForm | |
| 66 69 | 
             
                #
         | 
| 67 70 | 
             
                # You have some options for the input to enable/disable some functions:
         | 
| 68 71 | 
             
                #
         | 
| 69 | 
            -
                #   : | 
| 72 | 
            +
                #   as: allows you to define the input type you want, for instance you
         | 
| 70 73 | 
             
                #          can use it to generate a text field for a date column.
         | 
| 71 74 | 
             
                #
         | 
| 72 | 
            -
                #   : | 
| 75 | 
            +
                #   required: defines whether this attribute is required or not. True
         | 
| 73 76 | 
             
                #               by default.
         | 
| 74 77 | 
             
                #
         | 
| 75 78 | 
             
                # The fact SimpleForm is built in components allow the interface to be unified.
         | 
| 76 79 | 
             
                # So, for instance, if you need to disable :hint for a given input, you can pass
         | 
| 77 | 
            -
                # : | 
| 80 | 
            +
                # hint: false. The same works for :error, :label and :wrapper.
         | 
| 78 81 | 
             
                #
         | 
| 79 82 | 
             
                # Besides the html for any component can be changed. So, if you want to change
         | 
| 80 83 | 
             
                # the label html you just need to give a hash to :label_html. To configure the
         | 
| @@ -85,18 +88,18 @@ module SimpleForm | |
| 85 88 | 
             
                # Some inputs, as datetime, time and select allow you to give extra options, like
         | 
| 86 89 | 
             
                # prompt and/or include blank. Such options are given in plainly:
         | 
| 87 90 | 
             
                #
         | 
| 88 | 
            -
                #    f.input :created_at, : | 
| 91 | 
            +
                #    f.input :created_at, include_blank: true
         | 
| 89 92 | 
             
                #
         | 
| 90 93 | 
             
                # == Collection
         | 
| 91 94 | 
             
                #
         | 
| 92 95 | 
             
                # When playing with collections (:radio_buttons, :check_boxes and :select
         | 
| 93 96 | 
             
                # inputs), you have three extra options:
         | 
| 94 97 | 
             
                #
         | 
| 95 | 
            -
                #   : | 
| 98 | 
            +
                #   collection: use to determine the collection to generate the radio or select
         | 
| 96 99 | 
             
                #
         | 
| 97 | 
            -
                #   : | 
| 100 | 
            +
                #   label_method: the method to apply on the array collection to get the label
         | 
| 98 101 | 
             
                #
         | 
| 99 | 
            -
                #   : | 
| 102 | 
            +
                #   value_method: the method to apply on the array collection to get the value
         | 
| 100 103 | 
             
                #
         | 
| 101 104 | 
             
                # == Priority
         | 
| 102 105 | 
             
                #
         | 
| @@ -130,14 +133,14 @@ module SimpleForm | |
| 130 133 | 
             
                # This is the output html (only the input portion, not the form):
         | 
| 131 134 | 
             
                #
         | 
| 132 135 | 
             
                #     <input class="string required" id="user_name" maxlength="100"
         | 
| 133 | 
            -
                #        name="user[name]"  | 
| 136 | 
            +
                #        name="user[name]" type="text" value="Carlos" />
         | 
| 134 137 | 
             
                #
         | 
| 135 138 | 
             
                def input_field(attribute_name, options={})
         | 
| 136 139 | 
             
                  options = options.dup
         | 
| 137 | 
            -
                  options[:input_html] = options.except(:as, :collection, :label_method, :value_method)
         | 
| 140 | 
            +
                  options[:input_html] = options.except(:as, :collection, :label_method, :value_method, *ATTRIBUTE_COMPONENTS)
         | 
| 138 141 | 
             
                  options = @defaults.deep_dup.deep_merge(options) if @defaults
         | 
| 139 142 |  | 
| 140 | 
            -
                  SimpleForm::Wrappers::Root.new( | 
| 143 | 
            +
                  SimpleForm::Wrappers::Root.new(ATTRIBUTE_COMPONENTS + [:input], wrapper: false).render find_input(attribute_name, options)
         | 
| 141 144 | 
             
                end
         | 
| 142 145 |  | 
| 143 146 | 
             
                # Helper for dealing with association selects/radios, generating the
         | 
| @@ -151,7 +154,7 @@ module SimpleForm | |
| 151 154 | 
             
                #     f.association :company          # Company.all
         | 
| 152 155 | 
             
                #   end
         | 
| 153 156 | 
             
                #
         | 
| 154 | 
            -
                #   f.association :company, : | 
| 157 | 
            +
                #   f.association :company, collection: Company.all(order: 'name')
         | 
| 155 158 | 
             
                #   # Same as using :order option, but overriding collection
         | 
| 156 159 | 
             
                #
         | 
| 157 160 | 
             
                # == Block
         | 
| @@ -166,6 +169,8 @@ module SimpleForm | |
| 166 169 | 
             
                #
         | 
| 167 170 | 
             
                # From the options above, only :collection can also be supplied.
         | 
| 168 171 | 
             
                #
         | 
| 172 | 
            +
                # Please note that the association helper is currently only tested with Active Record. Depending on the ORM you are using your mileage may vary.
         | 
| 173 | 
            +
                #
         | 
| 169 174 | 
             
                def association(association, options={}, &block)
         | 
| 170 175 | 
             
                  options = options.dup
         | 
| 171 176 |  | 
| @@ -179,7 +184,9 @@ module SimpleForm | |
| 179 184 |  | 
| 180 185 | 
             
                  options[:as] ||= :select
         | 
| 181 186 | 
             
                  options[:collection] ||= options.fetch(:collection) {
         | 
| 182 | 
            -
                    reflection. | 
| 187 | 
            +
                    conditions = reflection.options[:conditions]
         | 
| 188 | 
            +
                    conditions = conditions.call if conditions.respond_to?(:call)
         | 
| 189 | 
            +
                    reflection.klass.where(conditions).order(reflection.options[:order])
         | 
| 183 190 | 
             
                  }
         | 
| 184 191 |  | 
| 185 192 | 
             
                  attribute = case reflection.macro
         | 
| @@ -190,7 +197,6 @@ module SimpleForm | |
| 190 197 | 
             
                    else
         | 
| 191 198 | 
             
                      if options[:as] == :select
         | 
| 192 199 | 
             
                        html_options = options[:input_html] ||= {}
         | 
| 193 | 
            -
                        html_options[:size]   ||= 5
         | 
| 194 200 | 
             
                        html_options[:multiple] = true unless html_options.key?(:multiple)
         | 
| 195 201 | 
             
                      end
         | 
| 196 202 |  | 
| @@ -203,7 +209,7 @@ module SimpleForm | |
| 203 209 | 
             
                      :"#{reflection.name.to_s.singularize}_ids"
         | 
| 204 210 | 
             
                  end
         | 
| 205 211 |  | 
| 206 | 
            -
                  input(attribute, options.merge(: | 
| 212 | 
            +
                  input(attribute, options.merge(reflection: reflection))
         | 
| 207 213 | 
             
                end
         | 
| 208 214 |  | 
| 209 215 | 
             
                # Creates a button:
         | 
| @@ -216,8 +222,7 @@ module SimpleForm | |
| 216 222 | 
             
                # button implementation (3.2 forward (to delegate to the original when
         | 
| 217 223 | 
             
                # calling `f.button :button`.
         | 
| 218 224 | 
             
                #
         | 
| 219 | 
            -
                 | 
| 220 | 
            -
                alias_method :button_button, :button if method_defined?(:button)
         | 
| 225 | 
            +
                alias_method :button_button, :button
         | 
| 221 226 | 
             
                def button(type, *args, &block)
         | 
| 222 227 | 
             
                  options = args.extract_options!.dup
         | 
| 223 228 | 
             
                  options[:class] = [SimpleForm.button_class, options[:class]].compact
         | 
| @@ -235,7 +240,7 @@ module SimpleForm | |
| 235 240 | 
             
                # == Examples
         | 
| 236 241 | 
             
                #
         | 
| 237 242 | 
             
                #    f.error :name
         | 
| 238 | 
            -
                #    f.error :name, : | 
| 243 | 
            +
                #    f.error :name, id: "cool_error"
         | 
| 239 244 | 
             
                #
         | 
| 240 245 | 
             
                def error(attribute_name, options={})
         | 
| 241 246 | 
             
                  options = options.dup
         | 
| @@ -273,7 +278,7 @@ module SimpleForm | |
| 273 278 | 
             
                # == Examples
         | 
| 274 279 | 
             
                #
         | 
| 275 280 | 
             
                #    f.hint :name # Do I18n lookup
         | 
| 276 | 
            -
                #    f.hint :name, : | 
| 281 | 
            +
                #    f.hint :name, id: "cool_hint"
         | 
| 277 282 | 
             
                #    f.hint "Don't forget to accept this"
         | 
| 278 283 | 
             
                #
         | 
| 279 284 | 
             
                def hint(attribute_name, options={})
         | 
| @@ -300,10 +305,10 @@ module SimpleForm | |
| 300 305 | 
             
                #
         | 
| 301 306 | 
             
                #    f.label :name                     # Do I18n lookup
         | 
| 302 307 | 
             
                #    f.label :name, "Name"             # Same behavior as Rails, do not add required tag
         | 
| 303 | 
            -
                #    f.label :name, : | 
| 308 | 
            +
                #    f.label :name, label: "Name"   # Same as above, but adds required tag
         | 
| 304 309 | 
             
                #
         | 
| 305 | 
            -
                #    f.label :name, : | 
| 306 | 
            -
                #    f.label :name, : | 
| 310 | 
            +
                #    f.label :name, required: false
         | 
| 311 | 
            +
                #    f.label :name, id: "cool_label"
         | 
| 307 312 | 
             
                #
         | 
| 308 313 | 
             
                def label(attribute_name, *args)
         | 
| 309 314 | 
             
                  return super if args.first.is_a?(String) || block_given?
         | 
| @@ -324,13 +329,118 @@ module SimpleForm | |
| 324 329 | 
             
                # == Examples
         | 
| 325 330 | 
             
                #
         | 
| 326 331 | 
             
                #    f.error_notification
         | 
| 327 | 
            -
                #    f.error_notification : | 
| 328 | 
            -
                #    f.error_notification : | 
| 332 | 
            +
                #    f.error_notification message: 'Something went wrong'
         | 
| 333 | 
            +
                #    f.error_notification id: 'user_error_message', class: 'form_error'
         | 
| 329 334 | 
             
                #
         | 
| 330 335 | 
             
                def error_notification(options={})
         | 
| 331 336 | 
             
                  SimpleForm::ErrorNotification.new(self, options).render
         | 
| 332 337 | 
             
                end
         | 
| 333 338 |  | 
| 339 | 
            +
                # Create a collection of radio inputs for the attribute. Basically this
         | 
| 340 | 
            +
                # helper will create a radio input associated with a label for each
         | 
| 341 | 
            +
                # text/value option in the collection, using value_method and text_method
         | 
| 342 | 
            +
                # to convert these text/value. You can give a symbol or a proc to both
         | 
| 343 | 
            +
                # value_method and text_method, that will be evaluated for each item in
         | 
| 344 | 
            +
                # the collection.
         | 
| 345 | 
            +
                #
         | 
| 346 | 
            +
                # == Examples
         | 
| 347 | 
            +
                #
         | 
| 348 | 
            +
                #   form_for @user do |f|
         | 
| 349 | 
            +
                #     f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
         | 
| 350 | 
            +
                #   end
         | 
| 351 | 
            +
                #
         | 
| 352 | 
            +
                #   <input id="user_options_true" name="user[options]" type="radio" value="true" />
         | 
| 353 | 
            +
                #   <label class="collection_radio_buttons" for="user_options_true">Yes</label>
         | 
| 354 | 
            +
                #   <input id="user_options_false" name="user[options]" type="radio" value="false" />
         | 
| 355 | 
            +
                #   <label class="collection_radio_buttons" for="user_options_false">No</label>
         | 
| 356 | 
            +
                #
         | 
| 357 | 
            +
                # It is also possible to give a block that should generate the radio +
         | 
| 358 | 
            +
                # label. To wrap the radio with the label, for instance:
         | 
| 359 | 
            +
                #
         | 
| 360 | 
            +
                #   form_for @user do |f|
         | 
| 361 | 
            +
                #     f.collection_radio_buttons(
         | 
| 362 | 
            +
                #       :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
         | 
| 363 | 
            +
                #     ) do |b|
         | 
| 364 | 
            +
                #       b.label { b.radio_button + b.text }
         | 
| 365 | 
            +
                #     end
         | 
| 366 | 
            +
                #   end
         | 
| 367 | 
            +
                #
         | 
| 368 | 
            +
                # == Options
         | 
| 369 | 
            +
                #
         | 
| 370 | 
            +
                # Collection radio accepts some extra options:
         | 
| 371 | 
            +
                #
         | 
| 372 | 
            +
                #   * checked  => the value that should be checked initially.
         | 
| 373 | 
            +
                #
         | 
| 374 | 
            +
                #   * disabled => the value or values that should be disabled. Accepts a single
         | 
| 375 | 
            +
                #                 item or an array of items.
         | 
| 376 | 
            +
                #
         | 
| 377 | 
            +
                #   * collection_wrapper_tag   => the tag to wrap the entire collection.
         | 
| 378 | 
            +
                #
         | 
| 379 | 
            +
                #   * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
         | 
| 380 | 
            +
                #
         | 
| 381 | 
            +
                #   * item_wrapper_tag         => the tag to wrap each item in the collection.
         | 
| 382 | 
            +
                #
         | 
| 383 | 
            +
                #   * item_wrapper_class       => the CSS class to use for item_wrapper_tag
         | 
| 384 | 
            +
                #
         | 
| 385 | 
            +
                #   * a block                  => to generate the label + radio or any other component.
         | 
| 386 | 
            +
                def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
         | 
| 387 | 
            +
                  SimpleForm::Tags::CollectionRadioButtons.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
         | 
| 388 | 
            +
                end
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                # Creates a collection of check boxes for each item in the collection,
         | 
| 391 | 
            +
                # associated with a clickable label. Use value_method and text_method to
         | 
| 392 | 
            +
                # convert items in the collection for use as text/value in check boxes.
         | 
| 393 | 
            +
                # You can give a symbol or a proc to both value_method and text_method,
         | 
| 394 | 
            +
                # that will be evaluated for each item in the collection.
         | 
| 395 | 
            +
                #
         | 
| 396 | 
            +
                # == Examples
         | 
| 397 | 
            +
                #
         | 
| 398 | 
            +
                #   form_for @user do |f|
         | 
| 399 | 
            +
                #     f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
         | 
| 400 | 
            +
                #   end
         | 
| 401 | 
            +
                #
         | 
| 402 | 
            +
                #   <input name="user[options][]" type="hidden" value="" />
         | 
| 403 | 
            +
                #   <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
         | 
| 404 | 
            +
                #   <label class="collection_check_boxes" for="user_options_true">Yes</label>
         | 
| 405 | 
            +
                #   <input name="user[options][]" type="hidden" value="" />
         | 
| 406 | 
            +
                #   <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
         | 
| 407 | 
            +
                #   <label class="collection_check_boxes" for="user_options_false">No</label>
         | 
| 408 | 
            +
                #
         | 
| 409 | 
            +
                # It is also possible to give a block that should generate the check box +
         | 
| 410 | 
            +
                # label. To wrap the check box with the label, for instance:
         | 
| 411 | 
            +
                #
         | 
| 412 | 
            +
                #   form_for @user do |f|
         | 
| 413 | 
            +
                #     f.collection_check_boxes(
         | 
| 414 | 
            +
                #       :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
         | 
| 415 | 
            +
                #     ) do |b|
         | 
| 416 | 
            +
                #       b.label { b.check_box + b.text }
         | 
| 417 | 
            +
                #     end
         | 
| 418 | 
            +
                #   end
         | 
| 419 | 
            +
                #
         | 
| 420 | 
            +
                # == Options
         | 
| 421 | 
            +
                #
         | 
| 422 | 
            +
                # Collection check box accepts some extra options:
         | 
| 423 | 
            +
                #
         | 
| 424 | 
            +
                #   * checked  => the value or values that should be checked initially. Accepts
         | 
| 425 | 
            +
                #                 a single item or an array of items. It overrides existing associations.
         | 
| 426 | 
            +
                #
         | 
| 427 | 
            +
                #   * disabled => the value or values that should be disabled. Accepts a single
         | 
| 428 | 
            +
                #                 item or an array of items.
         | 
| 429 | 
            +
                #
         | 
| 430 | 
            +
                #   * collection_wrapper_tag   => the tag to wrap the entire collection.
         | 
| 431 | 
            +
                #
         | 
| 432 | 
            +
                #   * collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option
         | 
| 433 | 
            +
                #                                 is ignored if the :collection_wrapper_tag option is blank.
         | 
| 434 | 
            +
                #
         | 
| 435 | 
            +
                #   * item_wrapper_tag         => the tag to wrap each item in the collection.
         | 
| 436 | 
            +
                #
         | 
| 437 | 
            +
                #   * item_wrapper_class       => the CSS class to use for item_wrapper_tag
         | 
| 438 | 
            +
                #
         | 
| 439 | 
            +
                #   * a block                  => to generate the label + check box or any other component.
         | 
| 440 | 
            +
                def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
         | 
| 441 | 
            +
                  SimpleForm::Tags::CollectionCheckBoxes.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
         | 
| 442 | 
            +
                end
         | 
| 443 | 
            +
             | 
| 334 444 | 
             
                # Extract the model names from the object_name mess, ignoring numeric and
         | 
| 335 445 | 
             
                # explicit child indexes.
         | 
| 336 446 | 
             
                #
         | 
| @@ -339,10 +449,10 @@ module SimpleForm | |
| 339 449 | 
             
                # route[blocks_attributes][0][blocks_learning_object_attributes][1][foo_attributes]
         | 
| 340 450 | 
             
                # ["route", "blocks", "blocks_learning_object", "foo"]
         | 
| 341 451 | 
             
                #
         | 
| 342 | 
            -
                def lookup_model_names
         | 
| 452 | 
            +
                def lookup_model_names #:nodoc:
         | 
| 343 453 | 
             
                  @lookup_model_names ||= begin
         | 
| 344 454 | 
             
                    child_index = options[:child_index]
         | 
| 345 | 
            -
                    names = object_name.to_s.scan(/( | 
| 455 | 
            +
                    names = object_name.to_s.scan(/(?!\d)\w+/).flatten
         | 
| 346 456 | 
             
                    names.delete(child_index) if child_index
         | 
| 347 457 | 
             
                    names.each { |name| name.gsub!('_attributes', '') }
         | 
| 348 458 | 
             
                    names.freeze
         | 
| @@ -350,9 +460,9 @@ module SimpleForm | |
| 350 460 | 
             
                end
         | 
| 351 461 |  | 
| 352 462 | 
             
                # The action to be used in lookup.
         | 
| 353 | 
            -
                def lookup_action
         | 
| 463 | 
            +
                def lookup_action #:nodoc:
         | 
| 354 464 | 
             
                  @lookup_action ||= begin
         | 
| 355 | 
            -
                    action = template.controller.action_name
         | 
| 465 | 
            +
                    action = template.controller && template.controller.action_name
         | 
| 356 466 | 
             
                    return unless action
         | 
| 357 467 | 
             
                    action = action.to_sym
         | 
| 358 468 | 
             
                    ACTIONS[action] || action
         | 
| @@ -366,12 +476,6 @@ module SimpleForm | |
| 366 476 | 
             
                  column     = find_attribute_column(attribute_name)
         | 
| 367 477 | 
             
                  input_type = default_input_type(attribute_name, column, options)
         | 
| 368 478 |  | 
| 369 | 
            -
                  if input_type == :radio
         | 
| 370 | 
            -
                    SimpleForm.deprecation_warn "Using `:as => :radio` as input type is " \
         | 
| 371 | 
            -
                      "deprecated, please change it to `:as => :radio_buttons`."
         | 
| 372 | 
            -
                    input_type = :radio_buttons
         | 
| 373 | 
            -
                  end
         | 
| 374 | 
            -
             | 
| 375 479 | 
             
                  if block_given?
         | 
| 376 480 | 
             
                    SimpleForm::Inputs::BlockInput.new(self, attribute_name, column, input_type, options, &block)
         | 
| 377 481 | 
             
                  else
         | 
    
        data/lib/simple_form/helpers.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module SimpleForm
         | 
| 2 2 | 
             
              # Helpers are made of several helpers that cannot be turned on automatically.
         | 
| 3 3 | 
             
              # For instance, disabled cannot be turned on automatically, it requires the
         | 
| 4 | 
            -
              # user to explicitly pass the option : | 
| 4 | 
            +
              # user to explicitly pass the option disabled: true so it may work.
         | 
| 5 5 | 
             
              module Helpers
         | 
| 6 6 | 
             
                autoload :Autofocus,    'simple_form/helpers/autofocus'
         | 
| 7 7 | 
             
                autoload :Disabled,     'simple_form/helpers/disabled'
         | 
| @@ -24,7 +24,7 @@ module SimpleForm | |
| 24 24 | 
             
                  attr_reader :attribute_name, :column, :input_type, :reflection,
         | 
| 25 25 | 
             
                              :options, :input_html_options, :input_html_classes, :html_classes
         | 
| 26 26 |  | 
| 27 | 
            -
                  delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, : | 
| 27 | 
            +
                  delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder
         | 
| 28 28 |  | 
| 29 29 | 
             
                  class_attribute :default_options
         | 
| 30 30 | 
             
                  self.default_options = {}
         | 
| @@ -65,6 +65,10 @@ module SimpleForm | |
| 65 65 | 
             
                    @html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
         | 
| 66 66 |  | 
| 67 67 | 
             
                    @input_html_classes = @html_classes.dup
         | 
| 68 | 
            +
                    if SimpleForm.input_class && !input_html_classes.empty?
         | 
| 69 | 
            +
                      input_html_classes << SimpleForm.input_class
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
             | 
| 68 72 | 
             
                    @input_html_options = html_options_for(:input, input_html_classes).tap do |o|
         | 
| 69 73 | 
             
                      o[:readonly]  = true if has_readonly?
         | 
| 70 74 | 
             
                      o[:disabled]  = true if has_disabled?
         | 
| @@ -90,10 +94,6 @@ module SimpleForm | |
| 90 94 |  | 
| 91 95 | 
             
                  private
         | 
| 92 96 |  | 
| 93 | 
            -
                  def add_size!
         | 
| 94 | 
            -
                    input_html_options[:size] ||= [limit, SimpleForm.default_input_size].compact.min
         | 
| 95 | 
            -
                  end
         | 
| 96 | 
            -
             | 
| 97 97 | 
             
                  def limit
         | 
| 98 98 | 
             
                    if column
         | 
| 99 99 | 
             
                      decimal_or_float? ? decimal_limit : column_limit
         | 
| @@ -179,7 +179,7 @@ module SimpleForm | |
| 179 179 | 
             
                    lookups << :"defaults.#{reflection_or_attribute_name}"
         | 
| 180 180 | 
             
                    lookups << default
         | 
| 181 181 |  | 
| 182 | 
            -
                    I18n.t(lookups.shift, : | 
| 182 | 
            +
                    I18n.t(lookups.shift, scope: :"simple_form.#{namespace}", default: lookups).presence
         | 
| 183 183 | 
             
                  end
         | 
| 184 184 | 
             
                end
         | 
| 185 185 | 
             
              end
         | 
| @@ -4,7 +4,7 @@ module SimpleForm | |
| 4 4 | 
             
                  def input
         | 
| 5 5 | 
             
                    if nested_boolean_style?
         | 
| 6 6 | 
             
                      build_hidden_field_for_checkbox +
         | 
| 7 | 
            -
                        template.label_tag(nil, : | 
| 7 | 
            +
                        template.label_tag(nil, class: "checkbox") {
         | 
| 8 8 | 
             
                          build_check_box_without_hidden_field + inline_label
         | 
| 9 9 | 
             
                        }
         | 
| 10 10 | 
             
                    else
         | 
| @@ -17,6 +17,7 @@ module SimpleForm | |
| 17 17 | 
             
                      input
         | 
| 18 18 | 
             
                    elsif nested_boolean_style?
         | 
| 19 19 | 
             
                      html_options = label_html_options.dup
         | 
| 20 | 
            +
                      html_options[:class] ||= []
         | 
| 20 21 | 
             
                      html_options[:class].push(:checkbox)
         | 
| 21 22 |  | 
| 22 23 | 
             
                      build_hidden_field_for_checkbox +
         | 
| @@ -49,9 +50,10 @@ module SimpleForm | |
| 49 50 | 
             
                  # we need the hidden field to be *outside* the label (otherwise it
         | 
| 50 51 | 
             
                  # generates invalid html - html5 only).
         | 
| 51 52 | 
             
                  def build_hidden_field_for_checkbox
         | 
| 52 | 
            -
                     | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 53 | 
            +
                    options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
         | 
| 54 | 
            +
                    options[:name] = input_html_options[:name] if input_html_options.has_key?(:name)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    @builder.hidden_field(attribute_name, options)
         | 
| 55 57 | 
             
                  end
         | 
| 56 58 |  | 
| 57 59 | 
             
                  def inline_label
         | 
| @@ -7,8 +7,8 @@ module SimpleForm | |
| 7 7 | 
             
                  # "simple_form.no" keys. See the example locale file.
         | 
| 8 8 | 
             
                  def self.boolean_collection
         | 
| 9 9 | 
             
                    i18n_cache :boolean_collection do
         | 
| 10 | 
            -
                      [ [I18n.t(:"simple_form.yes", : | 
| 11 | 
            -
                        [I18n.t(:"simple_form.no", : | 
| 10 | 
            +
                      [ [I18n.t(:"simple_form.yes", default: 'Yes'), true],
         | 
| 11 | 
            +
                        [I18n.t(:"simple_form.no", default: 'No'), false] ]
         | 
| 12 12 | 
             
                    end
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| @@ -66,14 +66,14 @@ module SimpleForm | |
| 66 66 | 
             
                    collection_translated = translate_collection if collection_classes == [Symbol]
         | 
| 67 67 |  | 
| 68 68 | 
             
                    if collection_translated || collection_classes.include?(Array)
         | 
| 69 | 
            -
                      { : | 
| 69 | 
            +
                      { label: :first, value: :second }
         | 
| 70 70 | 
             
                    elsif collection_includes_basic_objects?(collection_classes)
         | 
| 71 | 
            -
                      { : | 
| 71 | 
            +
                      { label: :to_s, value: :to_s }
         | 
| 72 72 | 
             
                    else
         | 
| 73 73 | 
             
                      sample = collection.first || collection.last
         | 
| 74 74 |  | 
| 75 | 
            -
                      { : | 
| 76 | 
            -
                        : | 
| 75 | 
            +
                      { label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
         | 
| 76 | 
            +
                        value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
         | 
| 77 77 | 
             
                    end
         | 
| 78 78 | 
             
                  end
         | 
| 79 79 |  | 
| @@ -4,7 +4,6 @@ module SimpleForm | |
| 4 4 | 
             
                  enable :placeholder, :min_max
         | 
| 5 5 |  | 
| 6 6 | 
             
                  def input
         | 
| 7 | 
            -
                    add_size!
         | 
| 8 7 | 
             
                    input_html_classes.unshift("numeric")
         | 
| 9 8 | 
             
                    if html5?
         | 
| 10 9 | 
             
                      input_html_options[:type] ||= "number"
         | 
| @@ -14,11 +13,6 @@ module SimpleForm | |
| 14 13 | 
             
                  end
         | 
| 15 14 |  | 
| 16 15 | 
             
                  private
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  # Rails adds the size attr by default, if the :size key does not exist.
         | 
| 19 | 
            -
                  def add_size!
         | 
| 20 | 
            -
                    input_html_options[:size] ||= nil
         | 
| 21 | 
            -
                  end
         | 
| 22 16 | 
             
                end
         | 
| 23 17 | 
             
              end
         | 
| 24 18 | 
             
            end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            module SimpleForm
         | 
| 2 | 
            +
              module Tags
         | 
| 3 | 
            +
                module CollectionExtensions
         | 
| 4 | 
            +
                  private
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def render_collection
         | 
| 7 | 
            +
                    item_wrapper_tag   = @options.fetch(:item_wrapper_tag, :span)
         | 
| 8 | 
            +
                    item_wrapper_class = @options[:item_wrapper_class]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    @collection.map do |item|
         | 
| 11 | 
            +
                      value = value_for_collection(item, @value_method)
         | 
| 12 | 
            +
                      text  = value_for_collection(item, @text_method)
         | 
| 13 | 
            +
                      default_html_options = default_html_options_for_collection(item, value)
         | 
| 14 | 
            +
                      additional_html_options = option_html_attributes(item)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                      rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
         | 
| 19 | 
            +
                    end.join.html_safe
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def wrap_rendered_collection(collection)
         | 
| 23 | 
            +
                    wrapper_tag = @options[:collection_wrapper_tag]
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    if wrapper_tag
         | 
| 26 | 
            +
                      wrapper_class = @options[:collection_wrapper_class]
         | 
| 27 | 
            +
                      @template_object.content_tag(wrapper_tag, collection, class: wrapper_class)
         | 
| 28 | 
            +
                    else
         | 
| 29 | 
            +
                      collection
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                class CollectionRadioButtons < ActionView::Helpers::Tags::CollectionRadioButtons
         | 
| 35 | 
            +
                  include CollectionExtensions
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def render
         | 
| 38 | 
            +
                    wrap_rendered_collection(super)
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  private
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def render_component(builder)
         | 
| 44 | 
            +
                    builder.radio_button + builder.label(class: "collection_radio_buttons")
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                class CollectionCheckBoxes < ActionView::Helpers::Tags::CollectionCheckBoxes
         | 
| 49 | 
            +
                  include CollectionExtensions
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def render
         | 
| 52 | 
            +
                    wrap_rendered_collection(super)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  private
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def render_component(builder)
         | 
| 58 | 
            +
                    builder.check_box + builder.label(class: "collection_check_boxes")
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
    
        data/lib/simple_form/version.rb
    CHANGED