dry_crud 2.1.1 → 2.1.2

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.
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