simple_form 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of simple_form might be problematic. Click here for more details.

Files changed (38) hide show
  1. data/README.rdoc +30 -30
  2. data/lib/generators/simple_form/USAGE +1 -1
  3. data/lib/generators/simple_form/install_generator.rb +5 -6
  4. data/lib/generators/simple_form/templates/_form.html.haml +18 -0
  5. data/lib/generators/simple_form/templates/en.yml +14 -0
  6. data/lib/generators/simple_form/templates/simple_form.rb +21 -8
  7. data/lib/simple_form.rb +29 -8
  8. data/lib/simple_form/action_view_extensions/form_helper.rb +24 -1
  9. data/lib/simple_form/components.rb +5 -4
  10. data/lib/simple_form/components/errors.rb +13 -5
  11. data/lib/simple_form/components/hints.rb +1 -1
  12. data/lib/simple_form/components/label_input.rb +13 -0
  13. data/lib/simple_form/components/labels.rb +1 -1
  14. data/lib/simple_form/components/wrapper.rb +12 -2
  15. data/lib/simple_form/error_notification.rb +44 -0
  16. data/lib/simple_form/form_builder.rb +17 -1
  17. data/lib/simple_form/inputs.rb +1 -0
  18. data/lib/simple_form/inputs/base.rb +17 -9
  19. data/lib/simple_form/inputs/boolean_input.rb +22 -0
  20. data/lib/simple_form/inputs/collection_input.rb +6 -6
  21. data/lib/simple_form/inputs/date_time_input.rb +4 -4
  22. data/lib/simple_form/inputs/mapping_input.rb +0 -1
  23. data/lib/simple_form/inputs/numeric_input.rb +5 -1
  24. data/lib/simple_form/inputs/string_input.rb +5 -6
  25. data/lib/simple_form/version.rb +1 -1
  26. data/test/action_view_extensions/builder_test.rb +18 -18
  27. data/test/action_view_extensions/form_helper_test.rb +5 -5
  28. data/test/components/error_test.rb +14 -5
  29. data/test/components/hint_test.rb +1 -1
  30. data/test/components/label_test.rb +4 -3
  31. data/test/components/wrapper_test.rb +54 -0
  32. data/test/error_notification_test.rb +61 -0
  33. data/test/form_builder_test.rb +31 -11
  34. data/test/inputs_test.rb +55 -51
  35. data/test/support/mock_controller.rb +4 -4
  36. data/test/support/models.rb +11 -8
  37. data/test/test_helper.rb +8 -9
  38. metadata +30 -4
data/README.rdoc CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  Forms made easy (for Rails)!
4
4
 
5
- SimpleForm 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, this way letting you find how you find the better design for your eyes. Good part of the DSL was inherited from Formtastic, which we are thankful for and should make you feel right at home.
5
+ SimpleForm 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. Good part of the DSL was inherited from Formtastic, which we are thankful for and should make you feel right at home.
6
6
 
7
7
  == Installation
8
8
 
9
9
  Install the gem:
10
10
 
11
- sudo gem install simple_form
11
+ gem install simple_form
12
12
 
13
13
  Add it to your Gemfile:
14
14
 
@@ -18,7 +18,7 @@ Run the generator:
18
18
 
19
19
  rails generate simple_form:install
20
20
 
21
- And you are ready to go. Since this branch is aims Rails 3 support,
21
+ And you are ready to go. Since this branch aims Rails 3 support,
22
22
  if you want to use it with Rails 2.3 you should check this branch:
23
23
 
24
24
  http://github.com/plataformatec/simple_form/tree/v1.0
@@ -29,61 +29,61 @@ SimpleForm was designed to be customized as you need to. Basically it's a stack
29
29
 
30
30
  To start using SimpleForm you just have to use the helper it provides:
31
31
 
32
- <% simple_form_for @user do |f| -%>
32
+ <%= simple_form_for @user do |f| %>
33
33
  <%= f.input :username %>
34
34
  <%= f.input :password %>
35
35
  <%= f.button :submit %>
36
- <% end -%>
36
+ <% end %>
37
37
 
38
38
  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).
39
39
 
40
40
  You can overwrite the default label by passing it to the input method, or even add a hint:
41
41
 
42
- <% simple_form_for @user do |f| -%>
42
+ <%= simple_form_for @user do |f| %>
43
43
  <%= f.input :username, :label => 'Your username please' %>
44
44
  <%= f.input :password, :hint => 'No special characters.' %>
45
45
  <%= f.button :submit %>
46
- <% end -%>
46
+ <% end %>
47
47
 
48
48
  You can also disable labels, hints or error or configure the html of any of them:
49
49
 
50
- <% simple_form_for @user do |f| -%>
50
+ <%= simple_form_for @user do |f| %>
51
51
  <%= f.input :username, :label_html => { :class => 'my_class' } %>
52
52
  <%= f.input :password, :hint => false, :error_html => { :id => "password_error"} %>
53
53
  <%= f.input :password_confirmation, :label => false %>
54
54
  <%= f.button :submit %>
55
- <% end -%>
55
+ <% end %>
56
56
 
57
57
  By default all inputs are required, which means an * is prepended to the label, but you can disable it in any input you want:
58
58
 
59
- <% simple_form_for @user do |f| -%>
59
+ <%= simple_form_for @user do |f| %>
60
60
  <%= f.input :name, :required => false %>
61
61
  <%= f.input :username %>
62
62
  <%= f.input :password %>
63
63
  <%= f.button :submit %>
64
- <% end -%>
64
+ <% end %>
65
65
 
66
66
  SimpleForm also lets you overwrite the default input type it creates:
67
67
 
68
- <% simple_form_for @user do |f| -%>
68
+ <%= simple_form_for @user do |f| %>
69
69
  <%= f.input :username %>
70
70
  <%= f.input :password %>
71
71
  <%= f.input :description, :as => :text %>
72
72
  <%= f.input :accepts, :as => :radio %>
73
73
  <%= f.button :submit %>
74
- <% end -%>
74
+ <% end %>
75
75
 
76
76
  So instead of a checkbox for the :accepts attribute, you'll have a pair of radio buttons with yes/no labels and a text area instead of a text field for the description. You can also render boolean attributes using :as => :select to show a dropdown.
77
77
 
78
78
  SimpleForm also allows you using label, hint and error helpers it provides:
79
79
 
80
- <% simple_form_for @user do |f| -%>
80
+ <%= simple_form_for @user do |f| %>
81
81
  <%= f.label :username %>
82
82
  <%= f.text_field :username %>
83
83
  <%= f.error :username, :id => 'user_name_error' %>
84
84
  <%= f.hint 'No special characters, please!' %>
85
85
  <%= f.submit 'Save' %>
86
- <% end -%>
86
+ <% end %>
87
87
 
88
88
  Any extra option passed to label, hint or error will be rendered as html option.
89
89
 
@@ -91,11 +91,11 @@ Any extra option passed to label, hint or error will be rendered as html option.
91
91
 
92
92
  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:
93
93
 
94
- <% simple_form_for @user do |f| -%>
94
+ <%= simple_form_for @user do |f| %>
95
95
  <%= f.input :user %>
96
96
  <%= f.input :age, :collection => 18..60 %>
97
97
  <%= f.button :submit %>
98
- <% end -%>
98
+ <% end %>
99
99
 
100
100
  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 and :check_boxes. Those are added by SimpleForm to Rails set of form helpers (read Extra Helpers session below for more information).
101
101
 
@@ -125,17 +125,17 @@ The first step is to configure a wrapper tag:
125
125
 
126
126
  SimpleForm.wrapper_tag = :p
127
127
 
128
- And now, you don't need to wrap your f.input calls with anymore:
128
+ And now, you don't need to wrap your f.input calls anymore:
129
129
 
130
- <% simple_form_for @user do |f| -%>
130
+ <%= simple_form_for @user do |f| %>
131
131
  <%= f.input :username %>
132
132
  <%= f.input :password %>
133
133
  <%= f.button :submit %>
134
- <% end -%>
134
+ <% end %>
135
135
 
136
136
  == Associations
137
137
 
138
- To deal with associations, SimpleForm can generate select inputs or a series of radios or check boxes. Lets see how it works: imagine you have the user model that belongs to a company and has_and_belongs_to_many roles. The structure should be something like:
138
+ To deal with associations, SimpleForm can generate select inputs, a series of radios or check boxes. 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:
139
139
 
140
140
  class User < ActiveRecord::Base
141
141
  belongs_to :company
@@ -152,17 +152,17 @@ To deal with associations, SimpleForm can generate select inputs or a series of
152
152
 
153
153
  Now we have the user form:
154
154
 
155
- <% simple_form_for @user do |f| -%>
155
+ <%= simple_form_for @user do |f| %>
156
156
  <%= f.input :name %>
157
157
  <%= f.association :company %>
158
158
  <%= f.association :roles %>
159
159
  <%= f.button :submit %>
160
- <% end -%>
160
+ <% end %>
161
161
 
162
162
  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 radios and check boxes as well:
163
163
 
164
164
  f.association :company, :as => :radio
165
- f.association :roles, :as => :check_boxes
165
+ f.association :roles, :as => :check_boxes
166
166
 
167
167
  The association helper just invokes input under the hood, so all options available to :select, :radio and :check_boxes are also available to association. Additionally, you can specify the collection by hand, all together with the prompt:
168
168
 
@@ -172,10 +172,10 @@ The association helper just invokes input under the hood, so all options availab
172
172
 
173
173
  All web forms need buttons, right? SimpleForm wraps them in the DSL, acting like a proxy:
174
174
 
175
- <% simple_form_for @user do |f| -%>
175
+ <%= simple_form_for @user do |f| %>
176
176
  <%= f.input :name %>
177
177
  <%= f.button :submit %>
178
- <% end -%>
178
+ <% end %>
179
179
 
180
180
  The above will simply call submit. You choose to use it or not, it's just a question of taste.
181
181
 
@@ -236,9 +236,9 @@ SimpleForm comes with a lot of default mappings:
236
236
  text text area text
237
237
  file file field string, responding to file methods
238
238
  hidden hidden field -
239
- integer text field integer
240
- float text field float
241
- decimal text field decimal
239
+ integer number field integer
240
+ float number field float
241
+ decimal number field decimal
242
242
  datetime datetime select datetime/timestamp
243
243
  date date select date
244
244
  time time select time
@@ -292,7 +292,7 @@ SimpleForm will always look for a default attribute translation if no specific i
292
292
 
293
293
  Finally, you can also overwrite labels and hints inside your view, just by passing the label/hint manually. This way the I18n lookup will be skipped.
294
294
 
295
- There are other options that can be configured through I18n API, such as required text, boolean and button texts. Be sure to check our locale file or the one copied to your application after you run "script/generate simple_form_install".
295
+ There are other options that can be configured through I18n API, such as required text, boolean and button texts. Be sure to check our locale file or the one copied to your application after you run "rails generate simple_form:install".
296
296
 
297
297
  == Configuration
298
298
 
@@ -1,3 +1,3 @@
1
1
  To copy a SimpleForm initializer to your Rails App, with some configuration values, just do:
2
2
 
3
- script/generate simple_form_install
3
+ rails generate simple_form:install
@@ -2,10 +2,8 @@ module SimpleForm
2
2
  module Generators
3
3
  class InstallGenerator < Rails::Generators::Base
4
4
  desc "Copy SimpleForm default files"
5
-
6
- def self.source_root
7
- @_source_root = File.expand_path('../templates', __FILE__)
8
- end
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ class_option :template_engine
9
7
 
10
8
  def copy_initializers
11
9
  copy_file 'simple_form.rb', 'config/initializers/simple_form.rb'
@@ -16,8 +14,9 @@ module SimpleForm
16
14
  end
17
15
 
18
16
  def copy_scaffold_template
19
- copy_file '_form.html.erb', 'lib/templates/erb/scaffold/_form.html.erb'
17
+ engine = options[:template_engine]
18
+ copy_file "_form.html.#{engine}", "lib/templates/#{engine}/scaffold/_form.html.#{engine}"
20
19
  end
21
20
  end
22
21
  end
23
- end
22
+ end
@@ -0,0 +1,18 @@
1
+ = simple_form_for(@<%= singular_name %>) do |f|
2
+ - if @<%= singular_name %>.errors.any?
3
+ #error_explanation
4
+ %h2
5
+ = pluralize(@<%= singular_name %>.errors.count, "error")
6
+ prohibited this <%= singular_name %> from being saved:
7
+
8
+ %ul
9
+ - @<%= singular_name %>.errors.full_messages.each do |msg|
10
+ %li= msg
11
+
12
+ .inputs
13
+ <%- attributes.each do |attribute| -%>
14
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
15
+ <%- end -%>
16
+
17
+ .actions
18
+ = f.button :submit
@@ -8,3 +8,17 @@ en:
8
8
  # You can uncomment the line below if you need to overwrite the whole required html.
9
9
  # When using html, text and mark won't be used.
10
10
  # html: '<abbr title="required">*</abbr>'
11
+ error_notification:
12
+ default_message: "Some errors were found, please take a look:"
13
+ # Labels and hints examples
14
+ # labels:
15
+ # password: 'Password'
16
+ # user:
17
+ # new:
18
+ # email: 'E-mail para efetuar o sign in.'
19
+ # edit:
20
+ # email: 'E-mail.'
21
+ # hints:
22
+ # username: 'User name to sign in.'
23
+ # password: 'No special characters, please.'
24
+
@@ -1,11 +1,9 @@
1
1
  # Use this setup block to configure all options available in SimpleForm.
2
2
  SimpleForm.setup do |config|
3
3
 
4
- # Components used by the form builder to generate a complete input. You can
5
- # remove any of them, change the order, or even add your own components in the
6
- # stack. By inheriting your component from SimpleForm::Components::Base you'll
7
- # have some extra helpers for free.
8
- # config.components = [ :label, :input, :hint, :error ]
4
+ # Components used by the form builder to generate a complete input. You can remove
5
+ # any of them, change the order, or even add your own components to the stack.
6
+ # config.components = [ :label_input, :hint, :error ]
9
7
 
10
8
  # Default tag used on hints.
11
9
  # config.hint_tag = :span
@@ -13,16 +11,31 @@ SimpleForm.setup do |config|
13
11
  # Default tag used on errors.
14
12
  # config.error_tag = :span
15
13
 
14
+ # Method used to tidy up errors.
15
+ # config.error_method = :first
16
+
17
+ # Default tag used for error notification helper.
18
+ # config.error_notification_tag = :p
19
+
16
20
  # You can wrap all inputs in a pre-defined tag.
17
21
  # config.wrapper_tag = :div
18
22
 
23
+ # CSS class to add to all wrapper tags.
24
+ # config.wrapper_class = :input
25
+
26
+ # CSS class to add to the wrapper if the field has errors.
27
+ # config.wrapper_error_class = :field_with_errors
28
+
19
29
  # How the label text should be generated altogether with the required text.
20
30
  # config.label_text = lambda { |label, required| "#{required} #{label}" }
21
31
 
22
- # Series of attemps to detect a default label method for collection
32
+ # Whether attributes are required by default (or not). Default is true.
33
+ # config.required_by_default = true
34
+
35
+ # Series of attemps to detect a default label method for collection.
23
36
  # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
24
37
 
25
- # Series of attemps to detect a default value method for collection
38
+ # Series of attemps to detect a default value method for collection.
26
39
  # config.collection_value_methods = [ :id, :to_s ]
27
40
 
28
41
  # Collection of methods to detect if a file type was given.
@@ -34,6 +47,6 @@ SimpleForm.setup do |config|
34
47
  # Default priority for country inputs.
35
48
  # config.country_priority = nil
36
49
 
37
- # Default size for text inputs
50
+ # Default size for text inputs.
38
51
  # config.default_input_size = 50
39
52
  end
data/lib/simple_form.rb CHANGED
@@ -3,11 +3,12 @@ require 'simple_form/action_view_extensions/form_helper'
3
3
  require 'simple_form/action_view_extensions/builder'
4
4
 
5
5
  module SimpleForm
6
- autoload :Components, 'simple_form/components'
7
- autoload :FormBuilder, 'simple_form/form_builder'
8
- autoload :I18nCache, 'simple_form/i18n_cache'
9
- autoload :Inputs, 'simple_form/inputs'
10
- autoload :MapType, 'simple_form/map_type'
6
+ autoload :Components, 'simple_form/components'
7
+ autoload :ErrorNotification, 'simple_form/error_notification'
8
+ autoload :FormBuilder, 'simple_form/form_builder'
9
+ autoload :I18nCache, 'simple_form/i18n_cache'
10
+ autoload :Inputs, 'simple_form/inputs'
11
+ autoload :MapType, 'simple_form/map_type'
11
12
 
12
13
  # Default tag used on hints.
13
14
  mattr_accessor :hint_tag
@@ -17,9 +18,17 @@ module SimpleForm
17
18
  mattr_accessor :error_tag
18
19
  @@error_tag = :span
19
20
 
21
+ # Method used to tidy up errors.
22
+ mattr_accessor :error_method
23
+ @@error_method = :first
24
+
25
+ # Default tag used for error notification helper.
26
+ mattr_accessor :error_notification_tag
27
+ @@error_notification_tag = :p
28
+
20
29
  # Components used by the form builder.
21
30
  mattr_accessor :components
22
- @@components = [ :label, :input, :hint, :error ]
31
+ @@components = [ :label_input, :hint, :error ]
23
32
 
24
33
  # Series of attemps to detect a default label method for collection.
25
34
  mattr_accessor :collection_label_methods
@@ -29,14 +38,26 @@ module SimpleForm
29
38
  mattr_accessor :collection_value_methods
30
39
  @@collection_value_methods = [ :id, :to_s ]
31
40
 
32
- # You can wrap all inputs in a pre-defined tag. By default is nil.
41
+ # You can wrap all inputs in a pre-defined tag. Default is a div.
33
42
  mattr_accessor :wrapper_tag
34
43
  @@wrapper_tag = :div
35
44
 
45
+ # You can define the class to use on all wrappers. Default is input.
46
+ mattr_accessor :wrapper_class
47
+ @@wrapper_class = :input
48
+
49
+ # You can define the class to add to the wrapper when the field has errors. Default is fieldWithErrors.
50
+ mattr_accessor :wrapper_error_class
51
+ @@wrapper_error_class = :field_with_errors
52
+
36
53
  # How the label text should be generated altogether with the required text.
37
54
  mattr_accessor :label_text
38
55
  @@label_text = lambda { |label, required| "#{required} #{label}" }
39
56
 
57
+ # Whether attributes are required by default (or not).
58
+ mattr_accessor :required_by_default
59
+ @@required_by_default = true
60
+
40
61
  # Collection of methods to detect if a file type was given.
41
62
  mattr_accessor :file_methods
42
63
  @@file_methods = [ :mounted_as, :file?, :public_filename ]
@@ -53,7 +74,7 @@ module SimpleForm
53
74
  mattr_accessor :default_input_size
54
75
  @@default_input_size = 50
55
76
 
56
- # Default way to setup SimpleForm. Run script/generate simple_form_install
77
+ # Default way to setup SimpleForm. Run rails generate simple_form:install
57
78
  # to create a fresh initializer with all configuration values.
58
79
  def self.setup
59
80
  yield self
@@ -10,6 +10,26 @@ module SimpleForm
10
10
  # end
11
11
  #
12
12
  module FormHelper
13
+ # based on what is done in formtastic
14
+ # http://github.com/justinfrench/formtastic/blob/master/lib/formtastic.rb#L1706
15
+ @@default_field_error_proc = nil
16
+
17
+ # Override the default ActiveRecordHelper behaviour of wrapping the input.
18
+ # This gets taken care of semantically by adding an error class to the wrapper tag
19
+ # containing the input.
20
+ #
21
+ FIELD_ERROR_PROC = proc do |html_tag, instance_tag|
22
+ html_tag
23
+ end
24
+
25
+ def with_custom_field_error_proc(&block)
26
+ @@default_field_error_proc = ::ActionView::Base.field_error_proc
27
+ ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
28
+ result = yield
29
+ ::ActionView::Base.field_error_proc = @@default_field_error_proc
30
+ result
31
+ end
32
+
13
33
  [:form_for, :fields_for, :remote_form_for].each do |helper|
14
34
  class_eval <<-METHOD, __FILE__, __LINE__
15
35
  def simple_#{helper}(record_or_name_or_array, *args, &block)
@@ -22,7 +42,10 @@ module SimpleForm
22
42
  end
23
43
  options[:html] ||= {}
24
44
  options[:html][:class] = "simple_form \#{css_class} \#{options[:html][:class]}".strip
25
- #{helper}(record_or_name_or_array, *(args << options), &block)
45
+
46
+ with_custom_field_error_proc do
47
+ #{helper}(record_or_name_or_array, *(args << options), &block)
48
+ end
26
49
  end
27
50
  METHOD
28
51
  end
@@ -1,8 +1,9 @@
1
1
  module SimpleForm
2
2
  module Components
3
- autoload :Errors, 'simple_form/components/errors'
4
- autoload :Hints, 'simple_form/components/hints'
5
- autoload :Labels, 'simple_form/components/labels'
6
- autoload :Wrapper, 'simple_form/components/wrapper'
3
+ autoload :Errors, 'simple_form/components/errors'
4
+ autoload :Hints, 'simple_form/components/hints'
5
+ autoload :LabelInput, 'simple_form/components/label_input'
6
+ autoload :Labels, 'simple_form/components/labels'
7
+ autoload :Wrapper, 'simple_form/components/wrapper'
7
8
  end
8
9
  end
@@ -2,7 +2,7 @@ module SimpleForm
2
2
  module Components
3
3
  module Errors
4
4
  def error
5
- template.content_tag(error_tag, error_text, error_html_options) if object && errors.present?
5
+ template.content_tag(error_tag, error_text, error_html_options) if has_errors?
6
6
  end
7
7
 
8
8
  def error_tag
@@ -10,25 +10,33 @@ module SimpleForm
10
10
  end
11
11
 
12
12
  def error_text
13
- errors.to_sentence
13
+ errors.send(error_method)
14
+ end
15
+
16
+ def error_method
17
+ options[:error_method] || SimpleForm.error_method
14
18
  end
15
19
 
16
20
  def error_html_options
17
- html_options_for(:error, :error)
21
+ html_options_for(:error, [:error])
18
22
  end
19
23
 
20
24
  protected
21
25
 
26
+ def has_errors?
27
+ object && errors.present?
28
+ end
29
+
22
30
  def errors
23
31
  @errors ||= (errors_on_attribute + errors_on_association).compact
24
32
  end
25
33
 
26
34
  def errors_on_attribute
27
- Array(object.errors[attribute_name])
35
+ object.errors[attribute_name]
28
36
  end
29
37
 
30
38
  def errors_on_association
31
- reflection ? Array(object.errors[reflection.name]) : []
39
+ reflection ? object.errors[reflection.name] : []
32
40
  end
33
41
  end
34
42
  end