Class: Metadata::FormBuilder

Inherits:
BuilderBase
  • Object
show all
Defined in:
app/models/metadata/form_builder.rb

Overview

rubocop:todo Style/Documentation

Instance Attribute Summary

Attributes inherited from BuilderBase

#locals

Instance Method Summary collapse

Methods inherited from BuilderBase

#view_for

Constructor Details

#initialize(*args, &block) ⇒ FormBuilder

Returns a new instance of FormBuilder.


2
3
4
5
6
7
8
9
10
11
# File 'app/models/metadata/form_builder.rb', line 2

def initialize(*args, &block)
  super
  view_for(:field, 'shared/metadata/edit_field')
  view_for(:radio_field, 'shared/metadata/radio_field')
  view_for(:header, 'shared/metadata/header')
  view_for(:document, 'shared/metadata/edit_document_field')
  view_for(:checktext, 'shared/metadata/edit_checktext_field')

  @related_fields, @changing = [], []
end

Instance Method Details

#change_select_options_for(field, options) ⇒ Object

Allows the options of the specified 'field' to be changed based on the value of another field.


123
124
125
126
127
128
129
130
# File 'app/models/metadata/form_builder.rb', line 123

def change_select_options_for(field, options)
  options[:values] = options[:values].inject({}) do |values, (key, value)|
    values.tap do
      Array(key).each { |k| values[k.to_s] = Array(value) }
    end
  end
  @changing.push([field, options])
end

#checktext_field(field, options = {}) ⇒ Object

Very broken looking combination of textbox and option field. Seems to allow specifying N/A or the value from the text box. Text box appears to get rendered twice, which appears to be a bug.


39
40
41
42
43
44
45
# File 'app/models/metadata/form_builder.rb', line 39

def checktext_field(field, options = {})
  options[:class] ||= []
  options[:class] << ' form-control'
  property_field(:field, field) do
    render_view(:checktext, field, options)
  end
end

#document_field(field, options) ⇒ Object

Creates a file upload field that will be properly handled by Document instances. It's a bit of a hack because the field we're actually rendering is not what is requested in 'field', but 'field_attributes', so we have to also use a special view for it to alter that. – NOTE: This is immediately overridden by the block below so don't move it! ++


19
20
21
22
23
24
25
# File 'app/models/metadata/form_builder.rb', line 19

def document_field(field, options)
  property_field(:document, field, options) do
    fields_for(:"#{field}_attributes", builder: ActionView::Helpers::FormBuilder) do |fields|
      fields.file_field(:uploaded_data)
    end
  end
end

Renders the Javascript for dealing with showing and hiding the related fields.


133
134
135
136
137
138
139
140
141
142
143
# File 'app/models/metadata/form_builder.rb', line 133

def finalize_related_fields
  related = @related_fields.compact.uniq.map(&:to_s)
  concat(render(
           partial: 'shared/metadata/related_fields',
           locals: {
             root: sanitized_object_name,
             related: related,
             changing_fields: @changing
           }
         )) unless related.empty?
end

#header(field, options = {}) ⇒ Object


101
102
103
# File 'app/models/metadata/form_builder.rb', line 101

def header(field, options = {})
  render_view(:header, field, options)
end

#radio_select(method, choices, options = {}, html_options = {}) ⇒ Object


70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/metadata/form_builder.rb', line 70

def radio_select(method, choices, options = {}, html_options = {})
  group = html_options.delete(:grouping) || options.delete(:grouping)
  property_field(:radio_field, method, grouping: group) do
    choices.each_with_object(+''.html_safe) do |(label_text, option_value), output|
      output << tag.div(class: %w[custom-control custom-radio custom-control-inline]) do
        value = option_value || label_text
        concat radio_button(method, value, class: 'custom-control-input', required: true)
        concat label(method, label_text, class: 'custom-control-label', value: value)
      end
    end
  end
end

Handles wrapping certain fields so that they are only shown when another field is a certain value. You can use `:to` to give the name of the field, `:when` for the single value when the fields should be shown, and `:in` for a group of values. You must call finalize_related_fields at the end of your view to get the appropriate behaviour


109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/models/metadata/form_builder.rb', line 109

def related_fields(options, &block)
  options.symbolize_keys!

  values = (options.fetch(:in, Array(options[:when])) - Array(options[:not])).map do |v|
    v.to_s.downcase.gsub(/[^a-z0-9]+/, '_')
  end
  content = capture(&block)
  concat(tag.div(content, class: [:related_to, options[:to], values].flatten.join(' ')))

  @related_fields.push(options[:to])
  content
end

#select(method, choices, options = {}, html_options = {}, &block) ⇒ Object


61
62
63
64
65
66
67
68
# File 'app/models/metadata/form_builder.rb', line 61

def select(method, choices, options = {}, html_options = {}, &block)
  group = html_options.delete(:grouping) || options.delete(:grouping)
  html_options[:class] ||= ''
  html_options[:class] << ' custom-select'
  property_field(:field, method, grouping: group) do
    super(method, choices, options, html_options, &block)
  end
end

#select_by_association(association, options = {}, html_options = {}) ⇒ Object


27
28
29
30
31
32
33
34
# File 'app/models/metadata/form_builder.rb', line 27

def select_by_association(association, options = {}, html_options = {})
  html_options[:class] ||= 'select2'
  association_target = association.to_s.classify.constantize
  if @object.send(association).nil? && association_target.default.present?
    options[:selected] = association_target.default.for_select_dropdown.last
  end
  select(:"#{association}_id", association_target.for_select_association, options, html_options)
end