formtastic 5.0.0 → 6.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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +0 -1
  3. data/.github/workflows/integration.yaml +36 -0
  4. data/.github/workflows/test.yml +26 -20
  5. data/.gitignore +2 -1
  6. data/Appraisals +23 -0
  7. data/CONTRIBUTING.md +27 -0
  8. data/Gemfile +5 -0
  9. data/MIT-LICENSE +1 -1
  10. data/README.md +14 -46
  11. data/RELEASE_PROCESS +0 -1
  12. data/Rakefile +1 -1
  13. data/formtastic.gemspec +17 -10
  14. data/gemfiles/rails_72.gemfile +9 -0
  15. data/gemfiles/rails_80.gemfile +9 -0
  16. data/gemfiles/rails_81.gemfile +9 -0
  17. data/gemfiles/rails_edge.gemfile +9 -0
  18. data/lib/formtastic/actions/input_action.rb +1 -1
  19. data/lib/formtastic/actions/link_action.rb +1 -1
  20. data/lib/formtastic/form_builder.rb +27 -27
  21. data/lib/formtastic/helpers/action_helper.rb +0 -1
  22. data/lib/formtastic/helpers/actions_helper.rb +1 -1
  23. data/lib/formtastic/helpers/errors_helper.rb +71 -14
  24. data/lib/formtastic/helpers/fieldset_wrapper.rb +1 -1
  25. data/lib/formtastic/helpers/form_helper.rb +3 -3
  26. data/lib/formtastic/helpers/input_helper.rb +5 -3
  27. data/lib/formtastic/i18n.rb +0 -1
  28. data/lib/formtastic/inputs/base/aria.rb +26 -0
  29. data/lib/formtastic/inputs/base/collections.rb +1 -1
  30. data/lib/formtastic/inputs/base/errors.rb +1 -1
  31. data/lib/formtastic/inputs/base/html.rb +1 -1
  32. data/lib/formtastic/inputs/base/labelling.rb +1 -1
  33. data/lib/formtastic/inputs/base/validations.rb +32 -8
  34. data/lib/formtastic/inputs/base.rb +7 -5
  35. data/lib/formtastic/inputs/country_input.rb +9 -6
  36. data/lib/formtastic/inputs/datalist_input.rb +2 -2
  37. data/lib/formtastic/inputs/number_input.rb +1 -1
  38. data/lib/formtastic/inputs/range_input.rb +1 -1
  39. data/lib/formtastic/inputs/time_zone_input.rb +1 -1
  40. data/lib/formtastic/version.rb +1 -1
  41. data/lib/formtastic.rb +6 -2
  42. data/lib/generators/formtastic/form/form_generator.rb +2 -3
  43. data/lib/generators/formtastic/install/install_generator.rb +0 -1
  44. data/lib/generators/formtastic/stylesheets/stylesheets_generator.rb +15 -0
  45. data/{app/assets/stylesheets → lib/generators/templates}/formtastic.css +4 -4
  46. data/lib/generators/templates/formtastic.rb +7 -1
  47. data/script/integration-template.rb +14 -11
  48. data/script/integration.sh +17 -4
  49. data/spec/action_class_finder_spec.rb +0 -1
  50. data/spec/actions/button_action_spec.rb +0 -1
  51. data/spec/actions/generic_action_spec.rb +2 -3
  52. data/spec/actions/input_action_spec.rb +0 -1
  53. data/spec/actions/link_action_spec.rb +0 -1
  54. data/spec/builder/custom_builder_spec.rb +0 -1
  55. data/spec/builder/error_proc_spec.rb +0 -1
  56. data/spec/builder/semantic_fields_for_spec.rb +72 -2
  57. data/spec/fast_spec_helper.rb +0 -1
  58. data/spec/generators/formtastic/stylesheets/stylesheets_generator_spec.rb +22 -0
  59. data/spec/helpers/actions_helper_spec.rb +0 -1
  60. data/spec/helpers/form_helper_spec.rb +0 -1
  61. data/spec/helpers/input_helper_spec.rb +12 -1
  62. data/spec/helpers/inputs_helper_spec.rb +1 -2
  63. data/spec/helpers/reflection_helper_spec.rb +0 -1
  64. data/spec/helpers/semantic_errors_helper_spec.rb +114 -7
  65. data/spec/i18n_spec.rb +1 -2
  66. data/spec/input_class_finder_spec.rb +0 -1
  67. data/spec/inputs/base/collections_spec.rb +41 -0
  68. data/spec/inputs/boolean_input_spec.rb +0 -1
  69. data/spec/inputs/check_boxes_input_spec.rb +1 -2
  70. data/spec/inputs/color_input_spec.rb +0 -1
  71. data/spec/inputs/country_input_spec.rb +5 -6
  72. data/spec/inputs/custom_input_spec.rb +0 -1
  73. data/spec/inputs/datalist_input_spec.rb +0 -1
  74. data/spec/inputs/date_picker_input_spec.rb +0 -1
  75. data/spec/inputs/date_select_input_spec.rb +1 -2
  76. data/spec/inputs/datetime_picker_input_spec.rb +0 -1
  77. data/spec/inputs/datetime_select_input_spec.rb +1 -2
  78. data/spec/inputs/email_input_spec.rb +0 -1
  79. data/spec/inputs/file_input_spec.rb +0 -1
  80. data/spec/inputs/hidden_input_spec.rb +0 -1
  81. data/spec/inputs/include_blank_spec.rb +0 -1
  82. data/spec/inputs/label_spec.rb +32 -1
  83. data/spec/inputs/number_input_spec.rb +0 -1
  84. data/spec/inputs/password_input_spec.rb +1 -2
  85. data/spec/inputs/phone_input_spec.rb +0 -1
  86. data/spec/inputs/placeholder_spec.rb +0 -1
  87. data/spec/inputs/radio_input_spec.rb +0 -1
  88. data/spec/inputs/range_input_spec.rb +0 -1
  89. data/spec/inputs/readonly_spec.rb +0 -1
  90. data/spec/inputs/search_input_spec.rb +0 -1
  91. data/spec/inputs/select_input_spec.rb +0 -1
  92. data/spec/inputs/string_input_spec.rb +67 -2
  93. data/spec/inputs/text_input_spec.rb +0 -1
  94. data/spec/inputs/time_picker_input_spec.rb +0 -1
  95. data/spec/inputs/time_select_input_spec.rb +1 -2
  96. data/spec/inputs/time_zone_input_spec.rb +0 -1
  97. data/spec/inputs/url_input_spec.rb +0 -1
  98. data/spec/inputs/with_options_spec.rb +0 -1
  99. data/spec/localizer_spec.rb +0 -1
  100. data/spec/namespaced_class_finder_spec.rb +0 -1
  101. data/spec/spec_helper.rb +2 -1
  102. data/spec/support/custom_macros.rb +11 -3
  103. data/spec/support/specialized_class_finder_shared_example.rb +0 -1
  104. data/spec/support/test_environment.rb +2 -2
  105. metadata +53 -41
  106. data/CHANGELOG.md +0 -61
  107. data/Gemfile.lock +0 -140
  108. data/app/assets/stylesheets/formtastic_ie6.css +0 -33
  109. data/app/assets/stylesheets/formtastic_ie7.css +0 -23
  110. data/gemfiles/rails_6.0/Gemfile +0 -5
  111. data/gemfiles/rails_6.1/Gemfile +0 -5
  112. data/gemfiles/rails_7.0/Gemfile +0 -5
  113. data/gemfiles/rails_7.1/Gemfile +0 -5
  114. data/gemfiles/rails_edge/Gemfile +0 -13
  115. data/lib/formtastic/engine.rb +0 -14
@@ -16,6 +16,10 @@ module Formtastic
16
16
  # A hash can be used as the last set of arguments to pass HTML attributes to the `<ul>`
17
17
  # wrapper.
18
18
  #
19
+ # # in config/initializers/formtastic.rb
20
+ # Setting `Formtastic::FormBuilder.semantic_errors_link_to_inputs = true`
21
+ # will render attribute errors as links to the corresponding errored inputs.
22
+ #
19
23
  # @example A list of errors on the base model
20
24
  # <%= semantic_form_for ... %>
21
25
  # <%= f.semantic_errors %>
@@ -41,24 +45,37 @@ module Formtastic
41
45
  # <% end %>
42
46
  def semantic_errors(*args)
43
47
  html_options = args.extract_options!
44
- args = args - [:base]
45
- full_errors = args.inject([]) do |array, method|
46
- attribute = localized_string(method, method.to_sym, :label) || humanized_attribute_name(method)
47
- errors = Array(@object.errors[method.to_sym]).to_sentence
48
- errors.present? ? array << [attribute, errors].join(" ") : array ||= []
49
- end
50
- full_errors << @object.errors[:base]
51
- full_errors.flatten!
52
- full_errors.compact!
53
- return nil if full_errors.blank?
54
48
  html_options[:class] ||= "errors"
55
- template.content_tag(:ul, html_options) do
56
- full_errors.map { |error| template.content_tag(:li, error) }.join.html_safe
49
+
50
+ if Formtastic::FormBuilder.semantic_errors_link_to_inputs
51
+ attribute_error_hash = semantic_error_hash_from_attributes(args)
52
+ return nil if @object.errors[:base].blank? && attribute_error_hash.blank?
53
+
54
+ template.content_tag(:ul, html_options) do
55
+ (
56
+ @object.errors[:base].map { |base_error| template.content_tag(:li, base_error) } <<
57
+ attribute_error_hash.map { |attribute, error_message|
58
+ template.content_tag(:li) do
59
+ template.content_tag(:a, href: "##{object_name}_#{attribute}") do
60
+ error_message
61
+ end
62
+ end
63
+ }
64
+ ).join.html_safe
65
+ end
66
+ else
67
+ full_errors = @object.errors[:base]
68
+ full_errors += semantic_error_list_from_attributes(args)
69
+ return nil if full_errors.blank?
70
+
71
+ template.content_tag(:ul, html_options) do
72
+ full_errors.map { |error| template.content_tag(:li, error) }.join.html_safe
73
+ end
57
74
  end
58
75
  end
59
-
76
+
60
77
  protected
61
-
78
+
62
79
  def error_keys(method, options)
63
80
  @methods_for_error ||= {}
64
81
  @methods_for_error[method] ||= begin
@@ -77,6 +94,46 @@ module Formtastic
77
94
  def render_inline_errors?
78
95
  @object && @object.respond_to?(:errors) && Formtastic::FormBuilder::INLINE_ERROR_TYPES.include?(inline_errors)
79
96
  end
97
+
98
+ def semantic_error_list_from_attributes(*args)
99
+ attribute_errors = []
100
+ args = args.flatten
101
+ args.each do |attribute|
102
+ next if attribute == :base
103
+
104
+ full_message = error_message_for_attribute(attribute)
105
+
106
+ attribute_errors << full_message unless full_message.blank?
107
+ end
108
+
109
+ attribute_errors
110
+ end
111
+
112
+ # returns { 'attribute': 'error_message_for_attribute' }
113
+ def semantic_error_hash_from_attributes(*args)
114
+ attribute_error_hash = {}
115
+ args = args.flatten
116
+ args.each do |attribute|
117
+ next if attribute == :base
118
+
119
+ full_message = error_message_for_attribute(attribute)
120
+
121
+ attribute_error_hash[attribute] = full_message unless full_message.blank?
122
+ end
123
+
124
+ attribute_error_hash
125
+ end
126
+
127
+ # Returns "Attribute error_message_sentence" localized, humanized
128
+ def error_message_for_attribute(attribute)
129
+ attribute_string = localized_string(attribute, attribute.to_sym, :label) || humanized_attribute_name(attribute)
130
+ error_message = @object.errors[attribute.to_sym]&.to_sentence
131
+
132
+ return nil if error_message.blank?
133
+
134
+ full_message = [attribute_string, error_message].join(" ")
135
+ full_message
136
+ end
80
137
  end
81
138
  end
82
139
  end
@@ -65,7 +65,7 @@ module Formtastic
65
65
 
66
66
  # Could be symbol for the association, or a model (or an array of either, I think? TODO)
67
67
  child = parent[:for]
68
- # Pull a sybol or model out of Array (TODO: check if there's an Array)
68
+ # Pull a symbol or model out of Array (TODO: check if there's an Array)
69
69
  child = child.first if child.respond_to?(:first)
70
70
  # If it's an object, get a symbol from the class name
71
71
  child = child.class.name.underscore.to_sym unless child.is_a?(Symbol)
@@ -59,7 +59,7 @@ module Formtastic
59
59
  @@default_form_class = 'formtastic'
60
60
  mattr_accessor :default_form_class
61
61
 
62
- # Allows to set a custom proc to handle the class infered from the model's name. By default it
62
+ # Allows to set a custom proc to handle the class inferred from the model's name. By default it
63
63
  # will infer the name from the class name (eg. Post will be "post").
64
64
  @@default_form_model_class_proc = proc { |model_class_name| model_class_name }
65
65
  mattr_accessor :default_form_model_class_proc
@@ -84,8 +84,8 @@ module Formtastic
84
84
  # Most of the examples below have been adapted from the examples found in the Rails `form_for`
85
85
  # documentation.
86
86
  #
87
- # @see http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html Rails' FormHelper documentation (`form_for`, etc)
88
- # @see http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html Rails' FormBuilder documentaion (`text_field`, etc)
87
+ # @see https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html Rails' FormHelper documentation (`form_for`, etc)
88
+ # @see https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html Rails' FormBuilder documentation (`text_field`, etc)
89
89
  # @see FormHelper The overview of the FormBuilder module
90
90
  #
91
91
  # @example Resource-oriented form generation
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # frozen_string_literal: true
3
2
  module Formtastic
4
3
  module Helpers
@@ -177,6 +176,9 @@ module Formtastic
177
176
  # @example Changing or adding to HTML attributes in the main `<input>` or `<select>` tag
178
177
  # <%= f.input :title, :input_html => { :onchange => "somethingAwesome();", :class => 'awesome' } %>
179
178
  #
179
+ # @example Changing or adding to HTML attributes in the main `<label>` tag
180
+ # <%= f.input :title, :label_html => { :data => { :tooltip => 'Great Tooltip' } } %>
181
+ #
180
182
  # @example Changing or adding to HTML attributes in the wrapper `<li>` tag
181
183
  # <%= f.input :title, :wrapper_html => { :class => "important-input" } %>
182
184
  #
@@ -278,7 +280,7 @@ module Formtastic
278
280
  return :number
279
281
  when :float, :decimal
280
282
  return :number
281
- when :datetime, :timestamp
283
+ when :datetime, :timestamp, :timestamptz
282
284
  return :datetime_select
283
285
  when :time
284
286
  return :time_select
@@ -290,7 +292,7 @@ module Formtastic
290
292
  return :string
291
293
  end
292
294
 
293
- # Try look for hints in options hash. Quite common senario: Enum keys stored as string in the database.
295
+ # Try look for hints in options hash. Quite common scenario: Enum keys stored as string in the database.
294
296
  return :select if column.type == :string && options.key?(:collection)
295
297
  # Try 3: Assume the input name will be the same as the column type (e.g. string_input).
296
298
  return column.type
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Formtastic
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Formtastic
3
+ module Inputs
4
+ module Base
5
+ module Aria
6
+
7
+ def error_aria_attributes
8
+ return {} unless builder.semantic_errors_link_to_inputs
9
+ return {} unless errors?
10
+
11
+ {
12
+ 'aria-describedby': describedby,
13
+ 'aria-invalid': options.dig(:input_html, :'aria-invalid') || 'true'
14
+ }
15
+ end
16
+
17
+ def describedby
18
+ describedby = options.dig(:input_html, :'aria-describedby') || ''
19
+ describedby += ' ' unless describedby.empty?
20
+ describedby += "#{method}_error"
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -53,7 +53,7 @@ module Formtastic
53
53
 
54
54
  # Return if we have an Array of strings, integers or arrays
55
55
  return raw_collection if (raw_collection.instance_of?(Array) || raw_collection.instance_of?(Range)) &&
56
- ([Array, String].include?(raw_collection.first.class) || raw_collection.first.is_a?(Integer)) &&
56
+ ([Array, String, Symbol].include?(raw_collection.first.class) || raw_collection.first.is_a?(Integer)) &&
57
57
  !(options.include?(:member_label) || options.include?(:member_value))
58
58
 
59
59
  raw_collection.map { |o| [send_or_call(label_method, o), send_or_call(value_method, o)] }
@@ -10,7 +10,7 @@ module Formtastic
10
10
 
11
11
  def error_sentence_html
12
12
  error_class = builder.default_inline_error_class
13
- template.content_tag(:p, errors.to_sentence, :class => error_class)
13
+ template.content_tag(:p, errors.to_sentence, id: "#{method}_error", :class => error_class)
14
14
  end
15
15
 
16
16
  def error_list_html
@@ -25,7 +25,7 @@ module Formtastic
25
25
  :required => required_attribute?,
26
26
  :autofocus => autofocus?,
27
27
  :readonly => readonly?
28
- }.merge(options[:input_html] || {})
28
+ }.merge(options[:input_html] || {}).merge(error_aria_attributes)
29
29
  end
30
30
 
31
31
  def dom_id
@@ -14,7 +14,7 @@ module Formtastic
14
14
  {
15
15
  :for => input_html_options[:id],
16
16
  :class => ['label'],
17
- }
17
+ }.merge(options[:label_html] || {})
18
18
  end
19
19
 
20
20
  def label_text
@@ -57,7 +57,8 @@ module Formtastic
57
57
  validation.kind == :length
58
58
  end
59
59
  if validation
60
- validation.options[:maximum] || (validation.options[:within].present? ? validation.options[:within].max : nil)
60
+ option_value(validation.options[:maximum], object) ||
61
+ (validation.options[:within].present? ? option_value(validation.options[:within], object).max : nil)
61
62
  else
62
63
  nil
63
64
  end
@@ -145,8 +146,8 @@ module Formtastic
145
146
  validator.options[:allow_blank] != true
146
147
  when :length
147
148
  validator.options[:allow_blank] != true &&
148
- validator.options[:minimum].to_i > 0 ||
149
- validator.options[:within].try(:first).to_i > 0
149
+ option_value(validator.options[:minimum], object).to_i > 0 ||
150
+ option_value(validator.options[:within], object).try(:first).to_i > 0
150
151
  else
151
152
  false
152
153
  end
@@ -183,7 +184,22 @@ module Formtastic
183
184
  end
184
185
 
185
186
  def column_limit
186
- column.limit if column? && column.respond_to?(:limit)
187
+ return unless column?
188
+ return unless column.respond_to?(:limit)
189
+
190
+ limit = column.limit # already in characters for string, text, etc
191
+
192
+ if column.type == :integer && column.limit.is_a?(Integer)
193
+ return {
194
+ 1 => 3, # 8 bit
195
+ 2 => 5, # 16 bit
196
+ 3 => 7, # 24 bit
197
+ 4 => 10, # 32 bit
198
+ 8 => 19, # 64 bit
199
+ }[limit] || nil
200
+ end
201
+
202
+ return limit
187
203
  end
188
204
 
189
205
  def limit
@@ -208,16 +224,24 @@ module Formtastic
208
224
 
209
225
  private
210
226
 
211
- # Loosely based on
212
- # https://github.com/rails/rails/blob/459e7cf62252558bbf65f582a230562ab1a76c5e/activemodel/lib/active_model/validations/numericality.rb#L65-L70
227
+ # Implements `ActiveModel::Validations::ResolveValue`, introduced by Rails 7.1.
228
+ # https://github.com/rails/rails/blob/v7.1.0/activemodel/lib/active_model/validations/resolve_value.rb
213
229
  def option_value(option, object)
214
230
  case option
215
231
  when Symbol
216
232
  object.send(option)
217
233
  when Proc
218
- option.call(object)
234
+ if option.arity == 0
235
+ option.call
236
+ else
237
+ option.call(object)
238
+ end
219
239
  else
220
- option
240
+ if option.respond_to?(:call)
241
+ option.call(object)
242
+ else
243
+ option
244
+ end
221
245
  end
222
246
  end
223
247
  end
@@ -19,22 +19,22 @@ module Formtastic
19
19
  warn_deprecated_option!(:member_value, member_deprecation_message)
20
20
  end
21
21
 
22
- # Usefull for deprecating options.
22
+ # Useful for deprecating options.
23
23
  def warn_and_correct_option!(old_option_name, new_option_name)
24
24
  if options.key?(old_option_name)
25
- Deprecation.warn("The :#{old_option_name} option is deprecated in favour of :#{new_option_name} and will be removed from Formtastic in the next version", caller(6))
25
+ Deprecation.warn("The :#{old_option_name} option is deprecated in favour of :#{new_option_name} and will be removed from Formtastic in the next version", caller_locations(6))
26
26
  options[new_option_name] = options.delete(old_option_name)
27
27
  end
28
28
  end
29
29
 
30
- # Usefull for deprecating options.
30
+ # Useful for deprecating options.
31
31
  def warn_deprecated_option!(old_option_name, instructions)
32
32
  if options.key?(old_option_name)
33
- Deprecation.warn("The :#{old_option_name} option is deprecated in favour of `#{instructions}`. :#{old_option_name} will be removed in the next version", caller(6))
33
+ Deprecation.warn("The :#{old_option_name} option is deprecated in favour of `#{instructions}`. :#{old_option_name} will be removed in the next version", caller_locations(6))
34
34
  end
35
35
  end
36
36
 
37
- # Usefull for raising an error on previously supported option.
37
+ # Useful for raising an error on previously supported option.
38
38
  def removed_option!(old_option_name)
39
39
  raise ArgumentError, ":#{old_option_name} is no longer available" if options.key?(old_option_name)
40
40
  end
@@ -59,6 +59,7 @@ module Formtastic
59
59
  autoload :Timeish
60
60
  autoload :Validations
61
61
  autoload :Wrapping
62
+ autoload :Aria
62
63
 
63
64
  include Html
64
65
  include Options
@@ -71,6 +72,7 @@ module Formtastic
71
72
  include Associations
72
73
  include Labelling
73
74
  include Wrapping
75
+ include Aria
74
76
 
75
77
  end
76
78
  end
@@ -5,13 +5,10 @@ module Formtastic
5
5
  # Rails doesn't come with a `country_select` helper by default any more, so you'll need to do
6
6
  # one of the following:
7
7
  #
8
- # * install the [country_select](https://github.com/stefanpenner/country_select) gem
8
+ # * install the [country_select](https://github.com/countries/country_select) gem
9
9
  # * install any other country_select plugin that behaves in a similar way
10
10
  # * roll your own `country_select` helper with the same args and options as the Rails one
11
11
  #
12
- # Formtastic supports both 1.x and 2.x of stefanpenner/country_select, but if you're upgrading
13
- # from 1.x, they behave quite differently, so please see their [upgrade instructions](https://github.com/stefanpenner/country_select/blob/master/UPGRADING.md).
14
- #
15
12
  # By default, Formtastic includes a handful of English-speaking countries as "priority
16
13
  # countries", which can be set in the `priority_countries` configuration array in the
17
14
  # formtastic.rb initializer to suit your market and user base (see README for more info on
@@ -71,12 +68,18 @@ module Formtastic
71
68
  CountrySelectPluginMissing = Class.new(StandardError)
72
69
 
73
70
  def to_html
74
- raise CountrySelectPluginMissing, "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
71
+ raise CountrySelectPluginMissing, "To use the :country input, please install a country_select plugin, like this one: https://github.com/countries/country_select" unless builder.respond_to?(:country_select)
75
72
  input_wrapping do
76
73
  label_html <<
77
- builder.country_select(method, priority_countries, input_options, input_html_options)
74
+ builder.country_select(method, input_options_including_priorities, input_html_options)
78
75
  end
79
76
  end
77
+
78
+ def input_options_including_priorities
79
+ return input_options unless priority_countries
80
+
81
+ input_options.merge(:priority_countries => priority_countries)
82
+ end
80
83
 
81
84
  def priority_countries
82
85
  options[:priority_countries] || builder.priority_countries
@@ -4,9 +4,9 @@ module Formtastic
4
4
  # Outputs a label and a text field, along with a datalist tag
5
5
  # datalist tag provides a list of options which drives a simple autocomplete
6
6
  # on the text field. This is a HTML5 feature, more info can be found at
7
- # {https://developer.mozilla.org/en/docs/Web/HTML/Element/datalist <datalist> at MDN}
7
+ # {https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/datalist <datalist> at MDN}
8
8
  # This input accepts a :collection option which takes data in all the usual formats accepted by
9
- # {http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select options_for_select}
9
+ # {https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select options_for_select}
10
10
  #
11
11
  # @example Input is used as follows
12
12
  # f.input :fav_book, :as => :datalist, :collection => Book.pluck(:name)
@@ -67,7 +67,7 @@ module Formtastic
67
67
  # <%= f.input :shoe_size, :as => :number, :input_html => { :in => 3..15, :step => 1 } %>
68
68
  #
69
69
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
70
- # @see http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
70
+ # @see https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
71
71
  class NumberInput
72
72
  include Base
73
73
  include Base::Numeric
@@ -66,7 +66,7 @@ module Formtastic
66
66
  # <%= f.input :shoe_size, :as => :range, :input_html => { :in => 3..15, :step => 1 } %>
67
67
  #
68
68
  # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
69
- # @see http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
69
+ # @see https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
70
70
  #
71
71
  class RangeInput
72
72
  include Base
@@ -39,7 +39,7 @@ module Formtastic
39
39
  # Formtastic::FormBuilder.priority_time_zones = [timezone1, timezone2]
40
40
  # ```
41
41
  #
42
- # See http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/time_zone_select for more information.
42
+ # See https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/time_zone_select for more information.
43
43
  #
44
44
  class TimeZoneInput
45
45
  include Base
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Formtastic
3
- VERSION = "5.0.0"
3
+ VERSION = "6.0.0"
4
4
  end
data/lib/formtastic.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
- require 'formtastic/engine' if defined?(::Rails)
4
2
 
5
3
  module Formtastic
6
4
  extend ActiveSupport::Autoload
@@ -42,3 +40,9 @@ module Formtastic
42
40
  end
43
41
 
44
42
  end
43
+
44
+ if defined?(::Rails)
45
+ ActiveSupport.on_load(:action_view) do
46
+ include Formtastic::Helpers::FormHelper
47
+ end
48
+ end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
  module Formtastic
4
3
  # Generates a Formtastic form partial based on an existing model. It will not overwrite existing
@@ -33,7 +32,7 @@ module Formtastic
33
32
  class_option :copy, :type => :boolean, :default => false, :group => :formtastic,
34
33
  :desc => 'Copy the generated code the clipboard instead of generating a partial file."'
35
34
 
36
- class_option :controller, :type => :string, :default => false, :group => :formtastic,
35
+ class_option :controller, :type => :string, :default => nil, :group => :formtastic,
37
36
  :desc => 'Generate for custom controller/view path - in case model and controller namespace is different, i.e. "admin/posts"'
38
37
 
39
38
  def create_or_show
@@ -43,7 +42,7 @@ module Formtastic
43
42
 
44
43
  if options[:copy]
45
44
  template = File.read("#{self.class.source_root}/_form.html.#{engine}")
46
- erb = ERB.new(template, nil, '-')
45
+ erb = ERB.new(template, trim_mode: '-')
47
46
  generated_code = erb.result(binding).strip rescue nil
48
47
  puts "The following code has been copied to the clipboard, just paste it in your views:" if save_to_clipboard(generated_code)
49
48
  puts generated_code || "Error: Nothing generated. Does the model exist?"
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Formtastic
@@ -0,0 +1,15 @@
1
+ module Formtastic
2
+ # Copies a stylesheet into to app/assets/stylesheets/formtastic.css
3
+ #
4
+ # @example
5
+ # !!!shell
6
+ # $ rails generate formtastic:stylesheets
7
+ class StylesheetsGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("../../../templates", __FILE__)
9
+
10
+ desc "Copies Formtastic example stylesheet into your app"
11
+ def copy_files
12
+ copy_file "formtastic.css", "app/assets/stylesheets/formtastic.css"
13
+ end
14
+ end
15
+ end
@@ -4,8 +4,8 @@ It's *strongly* suggested that you don't modify this file. Instead, load a new
4
4
  this one in your layouts (eg formtastic_changes.css) and override the styles to suit your needs.
5
5
  This will allow you to update formtastic.css with new releases without clobbering your own changes.
6
6
 
7
- This stylesheet forms part of the Formtastic Rails Plugin
8
- (c) 2008-2011 Justin French
7
+ This stylesheet forms part of the Formtastic Rails gem
8
+ (c) Justin French
9
9
 
10
10
  --------------------------------------------------------------------------------------------------*/
11
11
 
@@ -84,13 +84,13 @@ This stylesheet forms part of the Formtastic Rails Plugin
84
84
 
85
85
  /* BUTTONS & ACTIONS
86
86
  --------------------------------------------------------------------------------------------------*/
87
- .formtastic .buttons,
87
+ .formtastic .buttons,
88
88
  .formtastic .actions {
89
89
  overflow:hidden; /* clear containing floats */
90
90
  padding-left:25%;
91
91
  }
92
92
 
93
- .formtastic .button,
93
+ .formtastic .button,
94
94
  .formtastic .action {
95
95
  float:left;
96
96
  padding-right:0.5em;
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # Set the default text field size when input is a string. Default is nil.
@@ -110,3 +109,10 @@
110
109
 
111
110
  # Which columns to skip when automatically rendering a form without any fields specified.
112
111
  # Formtastic::FormBuilder.skipped_columns = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
112
+
113
+ # You can opt-in to accessibility features for the `semantic_errors` helper by setting
114
+ # this to true. Doing so will render the attributes in the error summary list
115
+ # as `<li> <a>` links to the inputs that have errors. the inline error sentence's id is added to
116
+ # the errored input's aria-describedby. This ensures that the errored input is read out with
117
+ # the inline error sentence's error explanation, aria-invalid is set to true for errored inputs
118
+ # Formtastic::FormBuilder.semantic_errors_link_to_inputs = true
@@ -1,20 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  gem 'formtastic', path: '..'
3
- gem 'bcrypt', '~> 3.1.7'
3
+ gem 'bcrypt'
4
4
  gem 'rails-dom-testing', group: :test
5
- gem 'rexml', '~> 3.2' # to compensate for missing dependency in selenium-webdriver
5
+
6
+ gem 'minitest', '~> 5.27' # TODO: Remove this line when the Rails version used for integration tests will include rails/rails#56202
6
7
 
7
8
  # to speed up bundle install, reuse the bundle path
8
9
  def bundle_path
9
10
  File.expand_path ENV.fetch('BUNDLE_PATH', 'vendor/bundle')
10
11
  end
11
12
 
12
- if Rails.version >= '6.2'
13
- gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails'"
14
- elsif Rails.version >= '6.1'
15
- gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails', branch: '6-1-stable'"
16
- elsif Rails.version >= '6.0'
17
- gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails', branch: '6-0-stable'"
13
+ if Rails.version >= '8.1'
14
+ gsub_file 'Gemfile', /gem "rails".*/, %(gem "rails", "~> #{Rails.version}", github: "rails/rails", branch: "8-1-stable")
15
+ elsif Rails.version >= '8.0'
16
+ gsub_file 'Gemfile', /gem "rails".*/, %(gem "rails", "~> #{Rails.version}", github: "rails/rails", branch: "8-0-stable")
17
+ elsif Rails.version >= '7.2'
18
+ gsub_file 'Gemfile', /gem "rails".*/, %(gem "rails", "~> #{Rails.version}", github: "rails/rails", branch: "7-2-stable")
18
19
  end
19
20
 
20
21
  ### Ensure Dummy App's Ruby version matches the current environments Ruby Version
@@ -26,8 +27,9 @@ if bundle_install?
26
27
  previous_bundle_path = bundle_path
27
28
 
28
29
  require "bundler"
29
- Bundler.with_clean_env do
30
- system("bundle install --jobs=3 --retry=3 --path=#{previous_bundle_path}")
30
+ Bundler.with_original_env do
31
+ system("bundle config set path '#{previous_bundle_path}'")
32
+ system("bundle install --jobs=3 --retry=3")
31
33
  end
32
34
  end
33
35
  end
@@ -40,12 +42,13 @@ formtastic = -> do
40
42
  generate(:scaffold, 'user name:string password:digest')
41
43
  generate('formtastic:install')
42
44
  generate('formtastic:form', 'user name password --force')
45
+ generate('formtastic:stylesheets')
43
46
 
44
47
  rails_command('db:migrate')
48
+ rails_command('assets:precompile')
45
49
 
46
50
  in_root do
47
51
  inject_into_class 'app/models/user.rb', 'User', " has_secure_password\n"
48
- inject_into_file 'app/assets/stylesheets/application.css', " *= require formtastic\n", before: ' *= require_self'
49
52
  inject_into_class 'test/controllers/users_controller_test.rb', 'UsersControllerTest', <<-RUBY
50
53
 
51
54
  test "should show form" do
@@ -4,16 +4,29 @@ set -e
4
4
  set -o verbose
5
5
 
6
6
  test_app=dummy
7
-
8
7
  rm -rf ${test_app}
9
8
 
10
- bundle exec rails new ${test_app} \
9
+ export RAILS_INTEGRATION_VERSION="8.1.2"
10
+ gem install rails -v ${RAILS_INTEGRATION_VERSION}
11
+ rails -v
12
+
13
+ rails new ${test_app} \
11
14
  --template=$(dirname "$0")/integration-template.rb \
12
15
  --skip-bootsnap \
16
+ --skip-brakeman \
17
+ --skip-bundler-audit \
18
+ --skip-ci \
19
+ --skip-git \
13
20
  --skip-javascript \
21
+ --skip-jbuilder \
22
+ --skip-kamal \
23
+ --skip-rubocop \
24
+ --skip-solid \
14
25
  --skip-spring \
15
- --skip-turbolinks
26
+ --skip-thruster
16
27
 
17
- cd ${test_app} && export BUNDLE_GEMFILE=Gemfile
28
+ cd ${test_app}
18
29
 
30
+ bundle add formtastic --path=../formtastic
31
+ bundle install
19
32
  bundle exec rake test