Class: ActiveAdmin::HasManyBuilder

Inherits:
SimpleDelegator
  • Object
show all
Defined in:
lib/active_admin/form_builder.rb

Overview

Decorates a FormBuilder with the additional attributes and methods to build a has_many block. Nested has_many blocks are handled by nested decorators.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(has_many_form, assoc, options) ⇒ HasManyBuilder

Returns a new instance of HasManyBuilder.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/active_admin/form_builder.rb', line 46

def initialize(has_many_form, assoc, options)
  super has_many_form
  @assoc = assoc
  @options = extract_custom_settings!(options.dup)
  @options.reverse_merge!(for: assoc)
  @options[:class] = [options[:class], "inputs has_many_fields"].compact.join(" ")

  if sortable_column
    @options[:for] = [assoc, sorted_children(sortable_column)]
  end
end

Instance Attribute Details

#assocObject (readonly)

Returns the value of attribute assoc.



41
42
43
# File 'lib/active_admin/form_builder.rb', line 41

def assoc
  @assoc
end

#destroy_optionObject (readonly)

Returns the value of attribute destroy_option.



44
45
46
# File 'lib/active_admin/form_builder.rb', line 44

def destroy_option
  @destroy_option
end

#headingObject (readonly)

Returns the value of attribute heading.



43
44
45
# File 'lib/active_admin/form_builder.rb', line 43

def heading
  @heading
end

#new_recordObject (readonly)

Returns the value of attribute new_record.



44
45
46
# File 'lib/active_admin/form_builder.rb', line 44

def new_record
  @new_record
end

#optionsObject (readonly)

Returns the value of attribute options.



42
43
44
# File 'lib/active_admin/form_builder.rb', line 42

def options
  @options
end

#remove_recordObject (readonly)

Returns the value of attribute remove_record.



44
45
46
# File 'lib/active_admin/form_builder.rb', line 44

def remove_record
  @remove_record
end

#sortable_columnObject (readonly)

Returns the value of attribute sortable_column.



43
44
45
# File 'lib/active_admin/form_builder.rb', line 43

def sortable_column
  @sortable_column
end

#sortable_startObject (readonly)

Returns the value of attribute sortable_start.



43
44
45
# File 'lib/active_admin/form_builder.rb', line 43

def sortable_start
  @sortable_start
end

Instance Method Details

#allow_destroy?(form_object) ⇒ Boolean (protected)

Returns:

  • (Boolean)


133
134
135
136
137
138
139
140
141
142
# File 'lib/active_admin/form_builder.rb', line 133

def allow_destroy?(form_object)
  !! case destroy_option
     when Symbol, String
       form_object.public_send destroy_option
     when Proc
       destroy_option.call form_object
     else
       destroy_option
     end
end

#assoc_klassObject (protected)



85
86
87
# File 'lib/active_admin/form_builder.rb', line 85

def assoc_klass
  @assoc_klass ||= __getobj__.object.class.reflect_on_association(assoc).klass
end

#content_has_many(&block) ⇒ Object (protected)



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/active_admin/form_builder.rb', line 89

def content_has_many(&block)
  form_block = proc do |form_builder|
    render_has_many_form(form_builder, options[:parent], &block)
  end

  template.assigns[:has_many_block] = true
  contents = without_wrapper { inputs(options, &form_block) }
  contents ||= "".html_safe

  js = new_record ? js_for_has_many(options[:class], &form_block) : ""
  contents << js
end

#default_headingObject (protected)



80
81
82
83
# File 'lib/active_admin/form_builder.rb', line 80

def default_heading
  assoc_klass.model_name.
    human(count: ::ActiveAdmin::Helpers::I18n::PLURAL_MANY_COUNT)
end

#extract_custom_settings!(options) ⇒ Object (protected)

remove options that should not render as attributes



70
71
72
73
74
75
76
77
78
# File 'lib/active_admin/form_builder.rb', line 70

def extract_custom_settings!(options)
  @heading = options.key?(:heading) ? options.delete(:heading) : default_heading
  @sortable_column = options.delete(:sortable)
  @sortable_start = options.delete(:sortable_start) || 0
  @new_record = options.key?(:new_record) ? options.delete(:new_record) : true
  @destroy_option = options.delete(:allow_destroy)
  @remove_record = options.delete(:remove_record)
  options
end

#has_many_actions(form_builder, contents) ⇒ Object (protected)



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/active_admin/form_builder.rb', line 109

def has_many_actions(form_builder, contents)
  if form_builder.object.new_record?
    contents << template.(:li) do
      remove_text = remove_record.is_a?(String) ? remove_record : I18n.t("active_admin.has_many_remove")
      template.link_to remove_text, "#", class: "button has_many_remove"
    end
  elsif allow_destroy?(form_builder.object)
    form_builder.input(
      :_destroy, as: :boolean,
                 wrapper_html: { class: "has_many_delete" },
                 label: I18n.t("active_admin.has_many_delete"))
  end

  if sortable_column
    form_builder.input sortable_column, as: :hidden

    contents << template.(:li, class: "handle") do
      I18n.t("active_admin.move")
    end
  end

  contents
end

#js_for_has_many(class_string, &form_block) ⇒ Object (protected)

Capture the ADD JS



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/active_admin/form_builder.rb', line 162

def js_for_has_many(class_string, &form_block)
  assoc_name = assoc_klass.model_name
  placeholder = "NEW_#{assoc_name.to_s.underscore.upcase.gsub(/\//, '_')}_RECORD"
  opts = {
    for: [assoc, assoc_klass.new],
    class: class_string,
    for_options: { child_index: placeholder }
  }
  html = template.capture { __getobj__.send(:inputs_for_nested_attributes, opts, &form_block) }
  text = new_record.is_a?(String) ? new_record : I18n.t("active_admin.has_many_new", model: assoc_name.human)

  template.link_to text, "#", class: "button has_many_add", data: {
    html: CGI.escapeHTML(html).html_safe, placeholder: placeholder
  }
end

#render(&block) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/active_admin/form_builder.rb', line 58

def render(&block)
  html = "".html_safe
  html << template.(:h3) { heading } if heading.present?
  html << template.capture { content_has_many(&block) }
  html = wrap_div_or_li(html)
  template.concat(html) if template.output_buffer
  html
end

#render_has_many_form(form_builder, parent, &block) ⇒ Object (protected)

Renders the Formtastic inputs then appends ActiveAdmin delete and sort actions.



103
104
105
106
107
# File 'lib/active_admin/form_builder.rb', line 103

def render_has_many_form(form_builder, parent, &block)
  index = parent && form_builder.send(:parent_child_index, parent)
  template.concat template.capture { yield(form_builder, index) }
  template.concat has_many_actions(form_builder, "".html_safe)
end

#sorted_children(column) ⇒ Object (protected)



144
145
146
147
148
149
# File 'lib/active_admin/form_builder.rb', line 144

def sorted_children(column)
  __getobj__.object.public_send(assoc).sort_by do |o|
    attribute = o.public_send column
    [attribute.nil? ? Float::INFINITY : attribute, o.id || Float::INFINITY]
  end
end

#without_wrapperObject (protected)



151
152
153
154
155
156
157
158
159
# File 'lib/active_admin/form_builder.rb', line 151

def without_wrapper
  is_being_wrapped = already_in_an_inputs_block
  self.already_in_an_inputs_block = false

  html = yield

  self.already_in_an_inputs_block = is_being_wrapped
  html
end

#wrap_div_or_li(html) ⇒ Object (protected)



178
179
180
181
182
183
184
185
# File 'lib/active_admin/form_builder.rb', line 178

def wrap_div_or_li(html)
  template.(
    already_in_an_inputs_block ? :li : :div,
    html,
    class: "has_many_container #{assoc}",
    "data-sortable" => sortable_column,
    "data-sortable-start" => sortable_start)
end