Module: NestedFormsHelper
- Defined in:
- app/helpers/nested_forms_helper.rb
Overview
View helper: nested forms.
Instance Method Summary collapse
-
#button_to_stimulus_nested_form(name, options = {}) ⇒ ActiveSupport::SafeBuffer
Stimulus-based nested forms using stimulus-components/rails-nested-form Stimulus-based nested forms — preferred for new code.
-
#generate_html(form_builder, method, options = {}) ⇒ String
Render the fields partial for a new (unsaved) nested-form record.
-
#link_to_new_nested_form(name, form_builder, method, options = {}, instance_defaults = nil) ⇒ ActiveSupport::SafeBuffer
Legacy nested forms (to be migrated to Stimulus).
-
#nested_form_delete_icon(f, selector, label_text = nil, **opts) ⇒ ActiveSupport::SafeBuffer
Keyword options (all optional): :icon, :icon_options (passed to fa_icon), :link_class, :title, :aria_label.
Instance Method Details
#button_to_stimulus_nested_form(name, options = {}) ⇒ ActiveSupport::SafeBuffer
Stimulus-based nested forms using stimulus-components/rails-nested-form
Stimulus-based nested forms — preferred for new code
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'app/helpers/nested_forms_helper.rb', line 182 def (name, = {}) css_classes = [] if [:class].present? css_classes << [:class] else css_classes += %w[btn btn-outline-primary] end = if block_given? yield elsif [:skip_icon].to_b name else fa_icon('circle-plus', text: name) end # Use the controller name from options or default to 'nested-form' controller_name = [:controller] || 'nested-form' data_hsh = { action: "#{controller_name}#add" }.merge([:data] || {}) .html_safe, id: [:id], type: 'button', class: css_classes.compact.uniq.join(' '), style: [:style], data: data_hsh end |
#generate_html(form_builder, method, options = {}) ⇒ String
Render the fields partial for a new (unsaved) nested-form record.
20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'app/helpers/nested_forms_helper.rb', line 20 def generate_html(form_builder, method, = {}) [:object] ||= form_builder.object.class.reflect_on_association(method).klass.new [:partial] ||= method.to_s.singularize [:form_builder_local] ||= :f [:partial_locals] ||= {} child_index = [:child_index] || 'NEW_RECORD' builder_method = form_builder.respond_to?(:simple_fields_for) ? :simple_fields_for : :fields_for form_builder.send(builder_method, method, [:object], child_index: child_index) do |f| render(partial: [:partial], locals: { [:form_builder_local] => f }.merge([:partial_locals])) end end |
#link_to_new_nested_form(name, form_builder, method, options = {}, instance_defaults = nil) ⇒ ActiveSupport::SafeBuffer
Legacy nested forms (to be migrated to Stimulus).
Pass use_stimulus_append: true to omit .new-nested-form and use .rma-add-items-nested-trigger
(rma-add-items Stimulus controller). Pass stimulus_nested_trigger_class: 'my-class' for a
page-specific trigger (rma-receive-items, etc.); that controller must handle the click.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'app/helpers/nested_forms_helper.rb', line 118 def link_to_new_nested_form(name, form_builder, method, = {}, instance_defaults = nil) instance_defaults ||= [:defaults] || {} [:object] ||= form_builder.object.class.reflect_on_association(method).klass.new(instance_defaults) [:partial] ||= method.to_s.singularize [:form_builder_local] ||= :f [:element_id] ||= method.to_s [:partial_locals] ||= {} html = generate_html(form_builder, method, object: [:object], partial: [:partial], form_builder_local: [:form_builder_local], partial_locals: [:partial_locals], child_index: [:child_index]) use_stimulus_append = [:use_stimulus_append] stimulus_trigger_class = [:stimulus_nested_trigger_class].to_s.presence css_classes = [] if [:class].present? css_classes << [:class] else css_classes += %w[btn btn-outline-primary] end css_classes << if stimulus_trigger_class stimulus_trigger_class elsif use_stimulus_append 'rma-add-items-nested-trigger' else 'new-nested-form' end link_label = if block_given? yield elsif [:skip_icon].to_b name else fa_icon('circle-plus', text: name) end data_hsh = { 'element-id': [:element_id], partial: h(html.to_s), trigger: [:trigger] }.merge([:data] || {}) link_to link_label.html_safe, '#', id: [:id], class: css_classes.compact.uniq.join(' '), style: [:style], data: data_hsh end |
#nested_form_delete_icon(f, selector, label_text = nil, **opts) ⇒ ActiveSupport::SafeBuffer
Keyword options (all optional): :icon, :icon_options (passed to fa_icon), :link_class, :title, :aria_label
Non-persisted branch: +icon_args+ is built from +icon_base+ (+icon_options+ dup). If both +label_text+
and +:text+ in +icon_options+ are present, +label_text+ wins (written into +icon_args[:text]+) and
Rails.logger.warn records the conflict.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'app/helpers/nested_forms_helper.rb', line 49 def nested_form_delete_icon(f, selector, label_text = nil, **opts) icon_name = (opts[:icon] || 'trash').to_s icon_base = (opts[:icon_options] || {}).dup extra_link_class = opts[:link_class].presence title = opts[:title] aria_label = opts[:aria_label] if f.object.present? && f.object.persisted? f.label '_destroy', class: 'p-0 m-0' do inner = fa_icon(icon_name, **icon_base) + f.check_box('_destroy') inner += tag.span(label_text, class: 'ms-1') if label_text.present? inner end else icon_args = icon_base.dup if label_text.present? && (icon_args.key?(:text) || icon_args.key?('text')) Rails.logger.warn( '[nested_form_delete_icon] label_text and icon_options[:text] were both set; ' \ "label_text wins and replaces icon_args[:text]. label_text=#{label_text.inspect}, " \ "icon_options=#{opts[:icon_options].inspect}, icon_base keys=#{icon_base.keys.inspect}" ) end if label_text.present? icon_args.delete('text') icon_args[:text] = label_text end link_classes = ['btn', 'trash-remove', 'p-0', 'm-0', extra_link_class].compact.join(' ') link_opts = { class: link_classes, 'data-class-to-remove': selector } link_opts[:title] = title if title.present? link_opts[:'aria-label'] = aria_label if aria_label.present? link_to fa_icon(icon_name, **icon_args), '#', **link_opts end end |