Class: DryCrud::Form::Builder

Inherits:
ActionView::Helpers::FormBuilder
  • Object
show all
Defined in:
app/helpers/dry_crud/form/builder.rb

Overview

A form builder that automatically selects the corresponding input field for ActiveRecord column types. Convenience methods for each column type allow one to customize the different fields.

All field methods may be prefixed with labeled_ in order to render a standard label, required mark and an optional help block with them.

Use #labeled_input_field or #input_field to render a input field corresponding to the given attribute.

See the Control class for how to customize the html rendered for a single input field.

Instance Attribute Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Dispatch methods starting with ‘labeled_’ to render a label and the corresponding input field. E.g. labeled_boolean_field(:checked, class: ‘bold’) To add an additional help text, use the help option. E.g. labeled_boolean_field(:checked, help: ‘Some Help’)



249
250
251
252
253
254
255
256
# File 'app/helpers/dry_crud/form/builder.rb', line 249

def method_missing(name, *args)
  field_method = labeled_field_method?(name)
  if field_method
    build_labeled_field(field_method, *args)
  else
    super
  end
end

Instance Attribute Details

#templateObject (readonly)

Returns the value of attribute template.



21
22
23
# File 'app/helpers/dry_crud/form/builder.rb', line 21

def template
  @template
end

Instance Method Details

#belongs_to_field(attr, **html_options) ⇒ Object

Render a select element for a :belongs_to association defined by attr. Use additional html_options for the select element. To pass a custom element list, specify the list with the :list key or define an instance variable with the pluralized name of the association.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'app/helpers/dry_crud/form/builder.rb', line 118

def belongs_to_field(attr, **html_options)
  list = association_entries(attr, **html_options).to_a
  if list.present?
    add_css_class(html_options, 'form-control')
    collection_select(attr, list, :id, :to_s,
                      select_options(attr, **html_options),
                      **html_options)
  else
    # rubocop:disable Rails/OutputSafety
    none = ta(:none_available, association(@object, attr)).html_safe
    # rubocop:enable Rails/OutputSafety
    static_text(none)
  end
end

#boolean_field(attr, **html_options) ⇒ Object

Render a boolean field.



72
73
74
75
76
77
78
79
# File 'app/helpers/dry_crud/form/builder.rb', line 72

def boolean_field(attr, **html_options)
  tag.div(class: 'checkbox') do
    tag.label do
      detail = html_options.delete(:detail) || ' '.html_safe
      safe_join([check_box(attr, html_options), ' ', detail])
    end
  end
end

Render a cancel link pointing to the given url.



189
190
191
192
# File 'app/helpers/dry_crud/form/builder.rb', line 189

def cancel_link(url = nil)
  url ||= cancel_url
  link_to(ti('button.cancel'), url, class: 'cancel')
end

#decimal_field(attr, **html_options) ⇒ Object



100
101
102
103
104
# File 'app/helpers/dry_crud/form/builder.rb', line 100

def decimal_field(attr, **html_options)
  html_options[:step] ||=
    (10**-column_property(object, attr, :scale)).to_f
  number_field(attr, **html_options)
end

#error_messagesObject

Render the error messages for the current form.



151
152
153
154
155
# File 'app/helpers/dry_crud/form/builder.rb', line 151

def error_messages
  @template.render('shared/error_messages',
                   errors: @object.errors,
                   object: @object)
end

#float_field(attr, **html_options) ⇒ Object



95
96
97
98
# File 'app/helpers/dry_crud/form/builder.rb', line 95

def float_field(attr, **html_options)
  html_options[:step] ||= 'any'
  number_field(attr, **html_options)
end

#has_many_field(attr, **html_options) ⇒ Object

Render a multi select element for a :has_many or :has_and_belongs_to_many association defined by attr. Use additional html_options for the select element. To pass a custom element list, specify the list with the :list key or define an instance variable with the pluralized name of the association.



141
142
143
144
145
# File 'app/helpers/dry_crud/form/builder.rb', line 141

def has_many_field(attr, **html_options)
  html_options[:multiple] = true
  add_css_class(html_options, 'multiselect')
  belongs_to_field(attr, **html_options)
end

#help_block(text) ⇒ Object

Generates a help block for fields



170
171
172
# File 'app/helpers/dry_crud/form/builder.rb', line 170

def help_block(text)
  tag.p(text, class: 'help-block')
end

#input_field(attr, **html_options) ⇒ Object

Render a corresponding input control for the given attribute. The input field is chosen based on the ActiveRecord column type.

The following options may be passed:

  • :addon - Addon content displayd just after the input field.

  • :help - A help text displayd below the input field.

  • :span - Number of columns the input field should span.

  • :field_method - Different method to create the input field.

Use additional html_options for the input element.



61
62
63
# File 'app/helpers/dry_crud/form/builder.rb', line 61

def input_field(attr, **html_options)
  control_class.new(self, attr, **html_options).render_content
end

#integer_field(attr, **html_options) ⇒ Object



90
91
92
93
# File 'app/helpers/dry_crud/form/builder.rb', line 90

def integer_field(attr, **html_options)
  html_options[:step] ||= 1
  number_field(attr, **html_options)
end

#labeled(attr, content = {}, options = {}, &block) ⇒ Object

Render a label for the given attribute with the passed content. The content may be given as an argument or as a block:

labeled(:attr) { #content }
labeled(:attr, content)

The following options may be passed:

  • :span - Number of columns the content should span.

  • :caption - Different caption for the label.



235
236
237
238
239
240
241
242
# File 'app/helpers/dry_crud/form/builder.rb', line 235

def labeled(attr, content = {}, options = {}, &block)
  if block_given?
    options = content
    content = capture(&block)
  end
  control = control_class.new(self, attr, **options)
  control.render_labeled(content)
end

#labeled_input_field(attr, **html_options) ⇒ Object

Render a corresponding input control and label for the given attribute. The input field is chosen based on the ActiveRecord column type.

The following options may be passed:

  • :addon - Addon content displayd just after the input field.

  • :help - A help text displayd below the input field.

  • :span - Number of columns the input field should span.

  • :caption - Different caption for the label.

  • :field_method - Different method to create the input field.

Use additional html_options for the input element.



47
48
49
# File 'app/helpers/dry_crud/form/builder.rb', line 47

def labeled_input_field(attr, **html_options)
  control_class.new(self, attr, **html_options).render_labeled
end

#labeled_input_fields(*attrs, **options) ⇒ Object

Render multiple input controls together with a label for the given attributes.



32
33
34
# File 'app/helpers/dry_crud/form/builder.rb', line 32

def labeled_input_fields(*attrs, **options)
  safe_join(attrs) { |a| labeled_input_field(a, **options.dup) }
end

#required?(attr) ⇒ Boolean

Returns true if the given attribute must be present.

Returns:

  • (Boolean)


216
217
218
219
220
221
222
223
224
225
# File 'app/helpers/dry_crud/form/builder.rb', line 216

def required?(attr)
  attr, attr_id = assoc_and_id_attr(attr)
  validators = @object.class.validators_on(attr) +
               @object.class.validators_on(attr_id)
  validators.any? do |v|
    v.kind == :presence &&
      !v.options.key?(:if) &&
      !v.options.key?(:unless)
  end
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Overriden to fullfill contract with method_missing ‘labeled_’ methods.

Returns:

  • (Boolean)


259
260
261
# File 'app/helpers/dry_crud/form/builder.rb', line 259

def respond_to_missing?(name, include_private = false)
  labeled_field_method?(name).present? || super
end

#select_options(attr, **options) ⇒ Object

Depending if the given attribute must be present, return only an initial selection prompt or a blank option, respectively.



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'app/helpers/dry_crud/form/builder.rb', line 196

def select_options(attr, **options)
  prompt = options.delete(:prompt)
  blank = options.delete(:include_blank)
  if options[:multiple]
    {}
  elsif prompt
    { prompt: prompt }
  elsif blank
    { include_blank: blank }
  else
    assoc = association(@object, attr)
    if required?(attr)
      { prompt: ta(:please_select, assoc) }
    else
      { include_blank: ta(:no_entry, assoc) }
    end
  end
end

#standard_actions(submit_label = ti('button.save'), cancel_url = nil) ⇒ Object

Render a submit button and a cancel link for this form.



175
176
177
178
179
180
181
# File 'app/helpers/dry_crud/form/builder.rb', line 175

def standard_actions(submit_label = ti('button.save'), cancel_url = nil)
  tag.div(class: 'col-md-offset-2 col-md-8') do
    safe_join([submit_button(submit_label),
               cancel_link(cancel_url)],
              ' ')
  end
end

#static_text(text) ⇒ Object

Renders a static text where otherwise form inputs appear.



165
166
167
# File 'app/helpers/dry_crud/form/builder.rb', line 165

def static_text(text)
  tag.p(text, class: 'form-control-static')
end

#string_field(attr, **html_options) ⇒ Object

Render a standard string field with column contraints.



66
67
68
69
# File 'app/helpers/dry_crud/form/builder.rb', line 66

def string_field(attr, **html_options)
  html_options[:maxlength] ||= column_property(@object, attr, :limit)
  text_field(attr, **html_options)
end

#submit_button(label = ti('button.save')) ⇒ Object

Render a standard submit button with the given label.



184
185
186
# File 'app/helpers/dry_crud/form/builder.rb', line 184

def submit_button(label = ti('button.save'))
  button(label, class: 'btn btn-primary', data: { disable_with: label })
end

#text_area(attr, **html_options) ⇒ Object

Customize the standard text area to have 5 rows by default.



107
108
109
110
111
# File 'app/helpers/dry_crud/form/builder.rb', line 107

def text_area(attr, **html_options)
  add_css_class(html_options, 'form-control')
  html_options[:rows] ||= 5
  super(attr, **html_options)
end

#with_addon(content, addon) ⇒ Object

Renders the given content with an addon.



158
159
160
161
162
# File 'app/helpers/dry_crud/form/builder.rb', line 158

def with_addon(content, addon)
  tag.div(class: 'input-group') do
    content + tag.span(addon, class: 'input-group-text')
  end
end