dry_crud 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +9 -9
  2. data/VERSION +1 -1
  3. data/app/assets/stylesheets/sample.scss +1 -1
  4. data/app/controllers/crud_controller.rb +1 -1
  5. data/app/controllers/dry_crud/generic_model.rb +45 -45
  6. data/app/controllers/dry_crud/nestable.rb +1 -1
  7. data/app/controllers/dry_crud/render_callbacks.rb +2 -0
  8. data/app/controllers/dry_crud/responder.rb +3 -0
  9. data/app/controllers/list_controller.rb +1 -1
  10. data/app/helpers/dry_crud/form/builder.rb +286 -261
  11. data/app/helpers/dry_crud/form/control.rb +156 -153
  12. data/app/helpers/dry_crud/table/actions.rb +69 -67
  13. data/app/helpers/dry_crud/table/builder.rb +96 -95
  14. data/app/helpers/dry_crud/table/col.rb +17 -16
  15. data/app/helpers/dry_crud/table/sorting.rb +48 -46
  16. data/app/helpers/format_helper.rb +2 -2
  17. data/app/helpers/table_helper.rb +2 -2
  18. data/lib/generators/dry_crud/file_generator.rb +2 -2
  19. data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +4 -6
  20. data/lib/generators/dry_crud/templates/spec/helpers/dry_crud/form/builder_spec.rb +11 -11
  21. data/lib/generators/dry_crud/templates/spec/helpers/form_helper_spec.rb +21 -21
  22. data/lib/generators/dry_crud/templates/spec/helpers/format_helper_spec.rb +21 -17
  23. data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +8 -8
  24. data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +11 -1
  25. data/lib/generators/dry_crud/templates/test/controllers/crud_test_models_controller_test.rb +6 -6
  26. data/lib/generators/dry_crud/templates/test/helpers/custom_assertions_test.rb +1 -0
  27. data/lib/generators/dry_crud/templates/test/helpers/dry_crud/form/builder_test.rb +250 -245
  28. data/lib/generators/dry_crud/templates/test/helpers/dry_crud/table/builder_test.rb +141 -128
  29. data/lib/generators/dry_crud/templates/test/helpers/form_helper_test.rb +54 -54
  30. data/lib/generators/dry_crud/templates/test/helpers/format_helper_test.rb +4 -4
  31. data/lib/generators/dry_crud/templates/test/helpers/table_helper_test.rb +1 -1
  32. data/lib/generators/dry_crud/templates/test/support/crud_controller_test_helper.rb +3 -2
  33. data/lib/generators/dry_crud/templates/test/support/crud_test_helper.rb +8 -8
  34. data/lib/generators/dry_crud/templates/test/support/crud_test_model.rb +0 -2
  35. data/lib/generators/dry_crud/templates/test/support/crud_test_models_controller.rb +7 -7
  36. data/lib/generators/dry_crud/templates/test/support/custom_assertions.rb +3 -3
  37. metadata +6 -6
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzE5OGExYmQyZDhkN2JiNGVmZjNjZGU5NTBlMTliZWU5ZTA5NDVkYw==
4
+ MWE4YzQzMjYxYmZlZWExOWUzZjczNDE2OWRlMTQwZDM4NDU5OTNlMg==
5
5
  data.tar.gz: !binary |-
6
- Yzk1Y2M5ZjJlZDk0MWYwZWUzMjA2NTc4YWMwZmUzMTlmYTdlODFjMw==
7
- !binary "U0hBNTEy":
6
+ OTUzZWFjODA5NzRlZTVlMGQzYzZiOTMzNGRkNjIxNDM4OWM0OTZlMw==
7
+ SHA512:
8
8
  metadata.gz: !binary |-
9
- OThmZjNlNTJhZDRkNWI5M2ZhYTBmYzQ1OGFlYTA0ZTVkYjFlZDkxN2U0MWNk
10
- OGQzMzViYWU3OWQwY2EzMjE4ZTc4OWNlYWMwNmVjNmRlNjY3N2VjMjY5YzNk
11
- ODhiZDAzZjUzYjVkZTMyM2ZmMDljNDNlYzRmZTM3ZDg4MTZiOWE=
9
+ MWY5NDJlYmQ2NjE1OGJlZjEzMGRlZmE1YmUzM2EzZDQ4Nzk3YjJhYzVhZWI5
10
+ OGQyNzI5OGJmMDgwYjU1N2Y3OTk5MjA2ZTgyNTU3OGI1NDhjODViNmJjZDVm
11
+ YWIyODY4YzIzODIxNDk2ZGQ4M2E2ODE4ZDQwOWQ2NmFjYTczYzE=
12
12
  data.tar.gz: !binary |-
13
- MThmZTk3YTQ5YWY0YWZlNDI5MDFlMmE3ZjAxZDgxNmU2ZDljN2UyNWFlZWI3
14
- OTY2NmQxYWUyMzQyYmZhNGZlMDU3NmYyNmVhYTRmMDc5MzhkNDlmOTkzNzFl
15
- ZGQ1OGYxNGIyNDgyY2U1ZGE5YzA5OGY0MWQ4ODMzNGJlOGJiNjM=
13
+ ODc3YTliNjQ5YzZhMGQwMjIxMTMwYzBlMDMzNDhjM2I5MDg0NzEwNGY0YTk0
14
+ NGRjN2Q2MWVkZjBhZjQzMmYzMTJhMDYyM2MwYzlkZGZmZTk0ZjY0NzVjMTE0
15
+ OTVmODcyNDNkNzUwNDJlNmIyN2E4NDFlZjhkZjIzZTY3NTRjYzM=
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.1
1
+ 2.1.2
@@ -224,7 +224,7 @@ a.icon img {
224
224
  padding: 4px 0 4px;
225
225
  }
226
226
 
227
- .form-group label {
227
+ .form-group > label {
228
228
  float: left;
229
229
  width: 120px;
230
230
  padding-right: 10px;
@@ -109,7 +109,7 @@ class CrudController < ListController
109
109
 
110
110
  # Main accessor method for the handled model entry.
111
111
  def entry
112
- get_model_ivar || set_model_ivar(params[:id] ? find_entry : build_entry)
112
+ model_ivar_get || model_ivar_set(params[:id] ? find_entry : build_entry)
113
113
  end
114
114
 
115
115
  # Creates a new model entry.
@@ -13,23 +13,23 @@ module DryCrud
13
13
  included do
14
14
  helper_method :model_class, :models_label, :path_args
15
15
 
16
- private
16
+ private
17
17
 
18
18
  delegate :model_class, :models_label, :model_identifier, to: 'self.class'
19
19
  end
20
20
 
21
21
  private
22
22
 
23
- # The scope where model entries will be listed and created.
24
- # This is mainly used for nested models to provide the
25
- # required context.
26
- def model_scope
27
- if Rails.version < '4.0'
28
- model_class.scoped
29
- else
30
- model_class.all
23
+ # The scope where model entries will be listed and created.
24
+ # This is mainly used for nested models to provide the
25
+ # required context.
26
+ def model_scope
27
+ if Rails.version < '4.0'
28
+ model_class.scoped
29
+ else
30
+ model_class.all
31
+ end
31
32
  end
32
- end
33
33
 
34
34
  # The path arguments to link to the given model entry.
35
35
  # If the controller is nested, this provides the required context.
@@ -37,53 +37,53 @@ module DryCrud
37
37
  last
38
38
  end
39
39
 
40
- # Get the instance variable named after the +model_class+.
41
- # If the collection variable is required, pass true as the second argument.
42
- def get_model_ivar(plural = false)
43
- name = ivar_name(model_class)
44
- name = name.pluralize if plural
45
- instance_variable_get(:"@#{name}")
46
- end
47
-
48
- # Sets an instance variable with the underscored class name if the given
49
- # value. If the value is a collection, sets the plural name.
50
- def set_model_ivar(value)
51
- name = if value.respond_to?(:klass) # ActiveRecord::Relation
52
- ivar_name(value.klass).pluralize
53
- elsif value.respond_to?(:each) # Array
54
- ivar_name(value.first.class).pluralize
55
- else
56
- ivar_name(value.class)
57
- end
58
- instance_variable_set(:"@#{name}", value)
59
- end
40
+ # Get the instance variable named after the +model_class+.
41
+ # If the collection variable is required, pass true as the second argument.
42
+ def model_ivar_get(plural = false)
43
+ name = ivar_name(model_class)
44
+ name = name.pluralize if plural
45
+ instance_variable_get(:"@#{name}")
46
+ end
60
47
 
61
- def ivar_name(klass)
62
- klass.model_name.param_key
63
- end
48
+ # Sets an instance variable with the underscored class name if the given
49
+ # value. If the value is a collection, sets the plural name.
50
+ def model_ivar_set(value)
51
+ name = if value.respond_to?(:klass) # ActiveRecord::Relation
52
+ ivar_name(value.klass).pluralize
53
+ elsif value.respond_to?(:each) # Array
54
+ ivar_name(value.first.class).pluralize
55
+ else
56
+ ivar_name(value.class)
57
+ end
58
+ instance_variable_set(:"@#{name}", value)
59
+ end
64
60
 
65
- # Class methods from GenericModel.
66
- module ClassMethods
67
- # The ActiveRecord class of the model.
68
- def model_class
69
- @model_class ||= controller_name.classify.constantize
61
+ def ivar_name(klass)
62
+ klass.model_name.param_key
70
63
  end
71
64
 
65
+ # Class methods from GenericModel.
66
+ module ClassMethods
67
+ # The ActiveRecord class of the model.
68
+ def model_class
69
+ @model_class ||= controller_name.classify.constantize
70
+ end
71
+
72
72
  # The identifier of the model used for form parameters.
73
73
  # I.e., the symbol of the underscored model name.
74
74
  def model_identifier
75
75
  @model_identifier ||= model_class.model_name.param_key
76
76
  end
77
77
 
78
- # A human readable plural name of the model.
79
- def models_label(plural = true)
80
- opts = { count: (plural ? 3 : 1) }
81
- opts[:default] = model_class.model_name.human.titleize
82
- opts[:default] = opts[:default].pluralize if plural
78
+ # A human readable plural name of the model.
79
+ def models_label(plural = true)
80
+ opts = { count: (plural ? 3 : 1) }
81
+ opts[:default] = model_class.model_name.human.titleize
82
+ opts[:default] = opts[:default].pluralize if plural
83
83
 
84
- model_class.model_name.human(opts)
84
+ model_class.model_name.human(opts)
85
+ end
85
86
  end
86
- end
87
87
 
88
88
  end
89
89
  end
@@ -45,7 +45,7 @@ module DryCrud
45
45
  # Loads the parent entry for the given ActiveRecord class.
46
46
  # By default, performs a find with the class_name_id param.
47
47
  def parent_entry(clazz)
48
- set_model_ivar(clazz.find(params["#{clazz.name.underscore}_id"]))
48
+ model_ivar_set(clazz.find(params["#{clazz.name.underscore}_id"]))
49
49
  end
50
50
 
51
51
  # An array of objects used in url_for and related functions.
@@ -37,6 +37,8 @@ module DryCrud
37
37
  # Defines before callbacks for the render actions.
38
38
  def define_render_callbacks(*actions)
39
39
  args = actions.map { |a| :"render_#{a}" }
40
+ # Rails 4.1 terminator:
41
+ # ->(ctrl, result) { result == false || ctrl.performed? }
40
42
  args << { only: :before,
41
43
  terminator: 'result == false || performed?' }
42
44
  define_model_callbacks(*args)
@@ -12,11 +12,14 @@ module DryCrud
12
12
 
13
13
  private
14
14
 
15
+ # rubocop:disable PredicateName
16
+
15
17
  # Check whether the resource has errors. Additionally checks the :success
16
18
  # option.
17
19
  def has_errors?
18
20
  options[:success] == false || super
19
21
  end
22
+ # rubocop:enable PredicateName
20
23
 
21
24
  # Wraps the resources with the path_args for correct nesting.
22
25
  def with_path_args(resources, controller)
@@ -35,7 +35,7 @@ class ListController < ApplicationController
35
35
  # Helper method to access the entries to be displayed in the current index
36
36
  # page in an uniform way.
37
37
  def entries
38
- get_model_ivar(true) || set_model_ivar(list_entries)
38
+ model_ivar_get(true) || model_ivar_set(list_entries)
39
39
  end
40
40
 
41
41
  # The base relation used to filter the entries.
@@ -1,314 +1,339 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module DryCrud::Form
4
-
5
- # A form builder that automatically selects the corresponding input field
6
- # for ActiveRecord column types. Convenience methods for each column type
7
- # allow one to customize the different fields.
8
- #
9
- # All field methods may be prefixed with +labeled_+ in order to render
10
- # a standard label, required mark and an optional help block with them.
11
- #
12
- # Use #labeled_input_field or #input_field to render a input field
13
- # corresponding to the given attribute.
14
- #
15
- # See the Control class for how to customize the html rendered for a
16
- # single input field.
17
- class Builder < ActionView::Helpers::FormBuilder
18
-
19
- class_attribute :control_class
20
- self.control_class = Control
21
-
22
- attr_reader :template
23
-
24
- delegate :association, :column_type, :column_property, :captionize,
25
- :ti, :ta, :link_to, :content_tag, :safe_join, :capture,
26
- :add_css_class, :assoc_and_id_attr,
27
- to: :template
28
-
29
- ### INPUT FIELDS
30
-
31
- # Render multiple input controls together with a label for the given
32
- # attributes.
33
- def labeled_input_fields(*attrs)
34
- options = attrs.extract_options!
35
- safe_join(attrs) { |a| labeled_input_field(a, options.dup) }
36
- end
3
+ module DryCrud
4
+ module Form
37
5
 
38
- # Render a corresponding input control and label for the given attribute.
39
- # The input field is chosen based on the ActiveRecord column type.
6
+ # A form builder that automatically selects the corresponding input field
7
+ # for ActiveRecord column types. Convenience methods for each column type
8
+ # allow one to customize the different fields.
40
9
  #
41
- # The following options may be passed:
42
- # * <tt>:addon</tt> - Addon content displayd just after the input field.
43
- # * <tt>:help</tt> - A help text displayd below the input field.
44
- # * <tt>:span</tt> - Number of columns the input field should span.
45
- # * <tt>:caption</tt> - Different caption for the label.
46
- # * <tt>:field_method</tt> - Different method to create the input field.
10
+ # All field methods may be prefixed with +labeled_+ in order to render
11
+ # a standard label, required mark and an optional help block with them.
47
12
  #
48
- # Use additional html_options for the input element.
49
- def labeled_input_field(attr, html_options = {})
50
- control_class.new(self, attr, html_options).render_labeled
51
- end
52
-
53
- # Render a corresponding input control for the given attribute.
54
- # The input field is chosen based on the ActiveRecord column type.
13
+ # Use #labeled_input_field or #input_field to render a input field
14
+ # corresponding to the given attribute.
55
15
  #
56
- # The following options may be passed:
57
- # * <tt>:addon</tt> - Addon content displayd just after the input field.
58
- # * <tt>:help</tt> - A help text displayd below the input field.
59
- # * <tt>:span</tt> - Number of columns the input field should span.
60
- # * <tt>:field_method</tt> - Different method to create the input field.
61
- #
62
- # Use additional html_options for the input element.
63
- def input_field(attr, html_options = {})
64
- control_class.new(self, attr, html_options).render_content
65
- end
16
+ # See the Control class for how to customize the html rendered for a
17
+ # single input field.
18
+ class Builder < ActionView::Helpers::FormBuilder
66
19
 
67
- # Render a standard string field with column contraints.
68
- def string_field(attr, html_options = {})
69
- html_options[:maxlength] ||= column_property(@object, attr, :limit)
70
- text_field(attr, html_options)
71
- end
20
+ class_attribute :control_class
21
+ self.control_class = Control
72
22
 
73
- # Render a boolean field.
74
- def boolean_field(attr, html_options = {})
75
- add_css_class(html_options, 'form-control')
76
- check_box(attr, html_options)
77
- end
23
+ attr_reader :template
78
24
 
79
- # Customize the standard text area to have 5 rows by default.
80
- def text_area(attr, html_options = {})
81
- html_options[:rows] ||= 5
82
- super
83
- end
25
+ delegate :association, :column_type, :column_property, :captionize,
26
+ :ti, :ta, :link_to, :content_tag, :safe_join, :capture,
27
+ :add_css_class, :assoc_and_id_attr,
28
+ to: :template
84
29
 
85
- alias_method :integer_field, :number_field
86
- alias_method :float_field, :number_field
87
- alias_method :decimal_field, :number_field
30
+ ### INPUT FIELDS
88
31
 
89
- if Rails.version < '4.0'
90
- # Render a field to select a date. You might want to customize this.
91
- def date_field(attr, html_options = {})
92
- html_options[:type] = 'date'
93
- text_field(attr, html_options)
32
+ # Render multiple input controls together with a label for the given
33
+ # attributes.
34
+ def labeled_input_fields(*attrs)
35
+ options = attrs.extract_options!
36
+ safe_join(attrs) { |a| labeled_input_field(a, options.dup) }
94
37
  end
95
38
 
96
- # Render a field to enter a time. You might want to customize this.
97
- def time_field(attr, html_options = {})
98
- html_options[:type] = 'time'
99
- text_field(attr, html_options)
39
+ # Render a corresponding input control and label for the given attribute.
40
+ # The input field is chosen based on the ActiveRecord column type.
41
+ #
42
+ # The following options may be passed:
43
+ # * <tt>:addon</tt> - Addon content displayd just after the input field.
44
+ # * <tt>:help</tt> - A help text displayd below the input field.
45
+ # * <tt>:span</tt> - Number of columns the input field should span.
46
+ # * <tt>:caption</tt> - Different caption for the label.
47
+ # * <tt>:field_method</tt> - Different method to create the input field.
48
+ #
49
+ # Use additional html_options for the input element.
50
+ def labeled_input_field(attr, html_options = {})
51
+ control_class.new(self, attr, html_options).render_labeled
100
52
  end
101
53
 
102
- # Render a field to enter a date and time.
103
- # You might want to customize this.
104
- def datetime_field(attr, html_options = {})
105
- html_options[:type] = 'datetime'
54
+ # Render a corresponding input control for the given attribute.
55
+ # The input field is chosen based on the ActiveRecord column type.
56
+ #
57
+ # The following options may be passed:
58
+ # * <tt>:addon</tt> - Addon content displayd just after the input field.
59
+ # * <tt>:help</tt> - A help text displayd below the input field.
60
+ # * <tt>:span</tt> - Number of columns the input field should span.
61
+ # * <tt>:field_method</tt> - Different method to create the input field.
62
+ #
63
+ # Use additional html_options for the input element.
64
+ def input_field(attr, html_options = {})
65
+ control_class.new(self, attr, html_options).render_content
66
+ end
67
+
68
+ # Render a standard string field with column contraints.
69
+ def string_field(attr, html_options = {})
70
+ html_options[:maxlength] ||= column_property(@object, attr, :limit)
106
71
  text_field(attr, html_options)
107
72
  end
108
- end
109
73
 
110
- # Render a select element for a :belongs_to association defined by attr.
111
- # Use additional html_options for the select element.
112
- # To pass a custom element list, specify the list with the :list key or
113
- # define an instance variable with the pluralized name of the association.
114
- def belongs_to_field(attr, html_options = {})
115
- list = association_entries(attr, html_options).to_a
116
- if list.present?
117
- collection_select(attr, list, :id, :to_s,
118
- select_options(attr, html_options),
119
- html_options)
120
- else
121
- static_text(ta(:none_available, association(@object, attr)).html_safe)
74
+ # Render a boolean field.
75
+ def boolean_field(attr, html_options = {})
76
+ content_tag(:div, class: 'checkbox') do
77
+ content_tag(:label) do
78
+ detail = html_options.delete(:detail) || '&nbsp;'.html_safe
79
+ safe_join([check_box(attr, html_options), ' ', detail])
80
+ end
81
+ end
122
82
  end
123
- end
124
83
 
125
- # Render a multi select element for a :has_many or :has_and_belongs_to_many
126
- # association defined by attr.
127
- # Use additional html_options for the select element.
128
- # To pass a custom element list, specify the list with the :list key or
129
- # define an instance variable with the pluralized name of the association.
130
- def has_many_field(attr, html_options = {})
131
- html_options[:multiple] = true
132
- add_css_class(html_options, 'multiselect')
133
- belongs_to_field(attr, html_options)
134
- end
84
+ # Add form-control class to all input fields.
85
+ %w(text_field password_field email_field text_area
86
+ number_fielc date_field time_field datetime_field).each do |method|
87
+ define_method(method) do |attr, html_options = {}|
88
+ add_css_class(html_options, 'form-control')
89
+ super(attr, html_options)
90
+ end
91
+ end
135
92
 
136
- ### VARIOUS FORM ELEMENTS
93
+ # Customize the standard text area to have 5 rows by default.
94
+ def text_area(attr, html_options = {})
95
+ add_css_class(html_options, 'form-control')
96
+ html_options[:rows] ||= 5
97
+ super(attr, html_options)
98
+ end
137
99
 
138
- # Render the error messages for the current form.
139
- def error_messages
140
- @template.render('shared/error_messages',
141
- errors: @object.errors,
142
- object: @object)
143
- end
100
+ alias_method :integer_field, :number_field
101
+ alias_method :float_field, :number_field
102
+ alias_method :decimal_field, :number_field
103
+
104
+ if Rails.version < '4.0'
105
+ # Render a field to select a date. You might want to customize this.
106
+ def date_field(attr, html_options = {})
107
+ html_options[:type] = 'date'
108
+ text_field(attr, html_options)
109
+ end
110
+
111
+ # Render a field to enter a time. You might want to customize this.
112
+ def time_field(attr, html_options = {})
113
+ html_options[:type] = 'time'
114
+ text_field(attr, html_options)
115
+ end
144
116
 
145
- # Renders the given content with an addon.
146
- def with_addon(content, addon)
147
- content_tag(:div, class: 'input-group') do
148
- content + content_tag(:span, addon, class: 'input-group-addon')
117
+ # Render a field to enter a date and time.
118
+ # You might want to customize this.
119
+ def datetime_field(attr, html_options = {})
120
+ html_options[:type] = 'datetime'
121
+ text_field(attr, html_options)
122
+ end
149
123
  end
150
- end
151
124
 
152
- # Renders a static text where otherwise form inputs appear.
153
- def static_text(text)
154
- content_tag(:p, text, class: 'form-control-static')
155
- end
125
+ # Render a select element for a :belongs_to association defined by attr.
126
+ # Use additional html_options for the select element.
127
+ # To pass a custom element list, specify the list with the :list key or
128
+ # define an instance variable with the pluralized name of the
129
+ # association.
130
+ def belongs_to_field(attr, html_options = {})
131
+ list = association_entries(attr, html_options).to_a
132
+ if list.present?
133
+ add_css_class(html_options, 'form-control')
134
+ collection_select(attr, list, :id, :to_s,
135
+ select_options(attr, html_options),
136
+ html_options)
137
+ else
138
+ static_text(
139
+ ta(:none_available, association(@object, attr)).html_safe)
140
+ end
141
+ end
156
142
 
157
- # Generates a help block for fields
158
- def help_block(text)
159
- content_tag(:p, text, class: 'help-block')
160
- end
143
+ # rubocop:disable PredicateName
144
+
145
+ # Render a multi select element for a :has_many or
146
+ # :has_and_belongs_to_many association defined by attr.
147
+ # Use additional html_options for the select element.
148
+ # To pass a custom element list, specify the list with the :list key or
149
+ # define an instance variable with the pluralized name of the
150
+ # association.
151
+ def has_many_field(attr, html_options = {})
152
+ html_options[:multiple] = true
153
+ add_css_class(html_options, 'multiselect')
154
+ belongs_to_field(attr, html_options)
155
+ end
156
+ # rubocop:enable PredicateName
157
+
158
+ ### VARIOUS FORM ELEMENTS
161
159
 
162
- # Render a submit button and a cancel link for this form.
163
- def standard_actions(submit_label = ti('button.save'), cancel_url = nil)
164
- content_tag(:div, class: 'col-md-offset-2 col-md-8') do
165
- safe_join([submit_button(submit_label), cancel_link(cancel_url)], ' ')
160
+ # Render the error messages for the current form.
161
+ def error_messages
162
+ @template.render('shared/error_messages',
163
+ errors: @object.errors,
164
+ object: @object)
166
165
  end
167
- end
168
166
 
169
- # Render a standard submit button with the given label.
170
- def submit_button(label = ti('button.save'))
171
- button(label, class: 'btn btn-primary', data: { disable_with: label })
172
- end
167
+ # Renders the given content with an addon.
168
+ def with_addon(content, addon)
169
+ content_tag(:div, class: 'input-group') do
170
+ content + content_tag(:span, addon, class: 'input-group-addon')
171
+ end
172
+ end
173
173
 
174
- # Render a cancel link pointing to the given url.
175
- def cancel_link(url = nil)
176
- url ||= cancel_url
177
- link_to(ti('button.cancel'), url, class: 'cancel')
178
- end
174
+ # Renders a static text where otherwise form inputs appear.
175
+ def static_text(text)
176
+ content_tag(:p, text, class: 'form-control-static')
177
+ end
179
178
 
180
- # Depending if the given attribute must be present, return
181
- # only an initial selection prompt or a blank option, respectively.
182
- def select_options(attr, options = {})
183
- prompt = options.delete(:prompt)
184
- blank = options.delete(:include_blank)
185
- if options[:multiple]
186
- {}
187
- elsif prompt
188
- { prompt: prompt }
189
- elsif blank
190
- { include_blank: blank }
191
- else
192
- assoc = association(@object, attr)
193
- if required?(attr)
194
- { prompt: ta(:please_select, assoc) }
195
- else
196
- { include_blank: ta(:no_entry, assoc) }
179
+ # Generates a help block for fields
180
+ def help_block(text)
181
+ content_tag(:p, text, class: 'help-block')
182
+ end
183
+
184
+ # Render a submit button and a cancel link for this form.
185
+ def standard_actions(submit_label = ti('button.save'), cancel_url = nil)
186
+ content_tag(:div, class: 'col-md-offset-2 col-md-8') do
187
+ safe_join([submit_button(submit_label),
188
+ cancel_link(cancel_url)],
189
+ ' ')
197
190
  end
198
191
  end
199
- end
200
192
 
201
- # Returns true if the given attribute must be present.
202
- def required?(attr)
203
- attr, attr_id = assoc_and_id_attr(attr)
204
- validators = @object.class.validators_on(attr) +
205
- @object.class.validators_on(attr_id)
206
- validators.any? do |v|
207
- v.kind == :presence &&
208
- !v.options.key?(:if) &&
209
- !v.options.key?(:unless)
193
+ # Render a standard submit button with the given label.
194
+ def submit_button(label = ti('button.save'))
195
+ button(label, class: 'btn btn-primary', data: { disable_with: label })
210
196
  end
211
- end
212
197
 
213
- # Render a label for the given attribute with the passed content.
214
- # The content may be given as an argument or as a block:
215
- # labeled(:attr) { #content }
216
- # labeled(:attr, content)
217
- #
218
- # The following options may be passed:
219
- # * <tt>:span</tt> - Number of columns the content should span.
220
- # * <tt>:caption</tt> - Different caption for the label.
221
- def labeled(attr, content = {}, options = {}, &block)
222
- if block_given?
223
- options = content
224
- content = capture(&block)
198
+ # Render a cancel link pointing to the given url.
199
+ def cancel_link(url = nil)
200
+ url ||= cancel_url
201
+ link_to(ti('button.cancel'), url, class: 'cancel')
225
202
  end
226
- control = control_class.new(self, attr, options)
227
- control.render_labeled(content)
228
- end
229
203
 
230
- # Dispatch methods starting with 'labeled_' to render a label and the
231
- # corresponding input field.
232
- # E.g. labeled_boolean_field(:checked, class: 'bold')
233
- # To add an additional help text, use the help option.
234
- # E.g. labeled_boolean_field(:checked, help: 'Some Help')
235
- def method_missing(name, *args)
236
- field_method = labeled_field_method?(name)
237
- if field_method
238
- build_labeled_field(field_method, *args)
239
- else
240
- super(name, *args)
204
+ # Depending if the given attribute must be present, return
205
+ # only an initial selection prompt or a blank option, respectively.
206
+ def select_options(attr, options = {})
207
+ prompt = options.delete(:prompt)
208
+ blank = options.delete(:include_blank)
209
+ if options[:multiple]
210
+ {}
211
+ elsif prompt
212
+ { prompt: prompt }
213
+ elsif blank
214
+ { include_blank: blank }
215
+ else
216
+ assoc = association(@object, attr)
217
+ if required?(attr)
218
+ { prompt: ta(:please_select, assoc) }
219
+ else
220
+ { include_blank: ta(:no_entry, assoc) }
221
+ end
222
+ end
241
223
  end
242
- end
243
224
 
244
- # Overriden to fullfill contract with method_missing 'labeled_' methods.
245
- def respond_to?(name)
246
- labeled_field_method?(name).present? || super(name)
247
- end
225
+ # Returns true if the given attribute must be present.
226
+ def required?(attr)
227
+ attr, attr_id = assoc_and_id_attr(attr)
228
+ validators = @object.class.validators_on(attr) +
229
+ @object.class.validators_on(attr_id)
230
+ validators.any? do |v|
231
+ v.kind == :presence &&
232
+ !v.options.key?(:if) &&
233
+ !v.options.key?(:unless)
234
+ end
235
+ end
236
+
237
+ # Render a label for the given attribute with the passed content.
238
+ # The content may be given as an argument or as a block:
239
+ # labeled(:attr) { #content }
240
+ # labeled(:attr, content)
241
+ #
242
+ # The following options may be passed:
243
+ # * <tt>:span</tt> - Number of columns the content should span.
244
+ # * <tt>:caption</tt> - Different caption for the label.
245
+ def labeled(attr, content = {}, options = {}, &block)
246
+ if block_given?
247
+ options = content
248
+ content = capture(&block)
249
+ end
250
+ control = control_class.new(self, attr, options)
251
+ control.render_labeled(content)
252
+ end
248
253
 
249
- private
254
+ # Dispatch methods starting with 'labeled_' to render a label and the
255
+ # corresponding input field.
256
+ # E.g. labeled_boolean_field(:checked, class: 'bold')
257
+ # To add an additional help text, use the help option.
258
+ # E.g. labeled_boolean_field(:checked, help: 'Some Help')
259
+ def method_missing(name, *args)
260
+ field_method = labeled_field_method?(name)
261
+ if field_method
262
+ build_labeled_field(field_method, *args)
263
+ else
264
+ super(name, *args)
265
+ end
266
+ end
250
267
 
251
- # Checks if the passed name corresponds to a field method with a
252
- # 'labeled_' prefix.
253
- def labeled_field_method?(name)
254
- prefix = 'labeled_'
255
- if name.to_s.start_with?(prefix)
256
- field_method = name.to_s[prefix.size..-1]
257
- field_method if respond_to?(field_method)
268
+ # Overriden to fullfill contract with method_missing 'labeled_' methods.
269
+ def respond_to?(name)
270
+ labeled_field_method?(name).present? || super(name)
258
271
  end
259
- end
260
272
 
261
- # Renders the corresponding field together with a label, required mark and
262
- # an optional help block.
263
- def build_labeled_field(field_method, *args)
264
- options = args.extract_options!
265
- options[:field_method] = field_method
266
- control_class.new(self, *(args << options)).render_labeled
267
- end
273
+ private
268
274
 
269
- # Returns the list of association entries, either from options[:list] or
270
- # the instance variable with the pluralized association name.
271
- # Otherwise, if the association defines a #options_list or #list scope,
272
- # this is used to load the entries.
273
- # As a last resort, all entries from the association class are returned.
274
- def association_entries(attr, options)
275
- list = options.delete(:list)
276
- unless list
277
- assoc = association(@object, attr)
278
- list = @template.send(:instance_variable_get,
279
- :"@#{assoc.name.to_s.pluralize}")
280
- list ||= load_association_entries(assoc)
275
+ # Checks if the passed name corresponds to a field method with a
276
+ # 'labeled_' prefix.
277
+ def labeled_field_method?(name)
278
+ prefix = 'labeled_'
279
+ if name.to_s.start_with?(prefix)
280
+ field_method = name.to_s[prefix.size..-1]
281
+ field_method if respond_to?(field_method)
282
+ end
283
+ end
284
+
285
+ # Renders the corresponding field together with a label, required mark
286
+ # and an optional help block.
287
+ def build_labeled_field(field_method, *args)
288
+ options = args.extract_options!
289
+ options[:field_method] = field_method
290
+ control_class.new(self, *(args << options)).render_labeled
281
291
  end
282
- list
283
- end
284
292
 
285
- # Automatically load the entries for the given association.
286
- def load_association_entries(assoc)
287
- klass = assoc.klass
288
- list = if Rails.version >= '4.0'
289
- klass.all.merge(assoc.scope)
290
- else
291
- klass.where(assoc.options[:conditions])
292
- .order(assoc.options[:order])
293
- end
294
- # Use special scopes if they are defined
295
- if klass.respond_to?(:options_list)
296
- list.options_list
297
- elsif klass.respond_to?(:list)
298
- list.list
299
- else
293
+ # Returns the list of association entries, either from options[:list] or
294
+ # the instance variable with the pluralized association name.
295
+ # Otherwise, if the association defines a #options_list or #list scope,
296
+ # this is used to load the entries.
297
+ # As a last resort, all entries from the association class are returned.
298
+ def association_entries(attr, options)
299
+ list = options.delete(:list)
300
+ unless list
301
+ assoc = association(@object, attr)
302
+ list = @template.send(:instance_variable_get,
303
+ :"@#{assoc.name.to_s.pluralize}")
304
+ list ||= load_association_entries(assoc)
305
+ end
300
306
  list
301
307
  end
302
- end
303
308
 
304
- # Get the cancel url for the given object considering options:
305
- # 1. Use :cancel_url_new or :cancel_url_edit option, if present
306
- # 2. Use :cancel_url option, if present
307
- def cancel_url
308
- url = @object.new_record? ? options[:cancel_url_new] :
309
- options[:cancel_url_edit]
310
- url || options[:cancel_url]
311
- end
309
+ # Automatically load the entries for the given association.
310
+ def load_association_entries(assoc)
311
+ klass = assoc.klass
312
+ list = if Rails.version >= '4.0'
313
+ klass.all.merge(assoc.scope)
314
+ else
315
+ klass.where(assoc.options[:conditions])
316
+ .order(assoc.options[:order])
317
+ end
318
+ # Use special scopes if they are defined
319
+ if klass.respond_to?(:options_list)
320
+ list.options_list
321
+ elsif klass.respond_to?(:list)
322
+ list.list
323
+ else
324
+ list
325
+ end
326
+ end
327
+
328
+ # Get the cancel url for the given object considering options:
329
+ # 1. Use :cancel_url_new or :cancel_url_edit option, if present
330
+ # 2. Use :cancel_url option, if present
331
+ def cancel_url
332
+ url = @object.new_record? ? options[:cancel_url_new] :
333
+ options[:cancel_url_edit]
334
+ url || options[:cancel_url]
335
+ end
312
336
 
337
+ end
313
338
  end
314
339
  end