Class: Compony::Components::Form
- Inherits:
-
Compony::Component
- Object
- Compony::Component
- Compony::Components::Form
- Defined in:
- lib/compony/components/form.rb
Overview
This component is used for the _form partial in the Rails paradigm.
Instance Attribute Summary
Attributes inherited from Compony::Component
#comp_opts, #content_blocks, #parent_comp
DSL collapse
-
#collect ⇒ Object
Quick access for wrapping collections in Rails compatible format.
-
#disable! ⇒ void
DSL method, disables all inputs.
-
#f ⇒ SimpleForm::FormBuilder
DSL method (inside
form_fields). -
#field(name, multilang: false, **input_opts) ⇒ String+
DSL method (inside
form_fields). -
#form_fields { ... } ⇒ Proc?
DSL method, use to set the form content (mandatory).
-
#form_params(**new_form_params) ⇒ void
DSL method, customizes the parameters given to
simple_form_for. -
#pw_field(name, **input_opts) ⇒ String?
DSL method (inside
form_fields). -
#schema(wrapper_key) { ... } ⇒ void
protected
DSL method, replaces the form's schema and wrapper key with a completely manual Schemacop3 schema.
-
#schema_block_for(data, controller) ⇒ Object
Attr reader for @schema_block with auto-calculated default.
-
#schema_field(field_name, multilang: false) ⇒ void
protected
DSL method, whitelists a single field of
data_classin the param schema, auto-generating the correct schema line. -
#schema_fields(*field_names) ⇒ void
protected
DSL method, whitelists several fields at once (see #schema_field).
-
#schema_line { ... } ⇒ void
protected
DSL method, adds a Schemacop3 line whitelisting param(s) inside the schema's wrapper.
-
#schema_pw_field(field_name) ⇒ void
protected
DSL method, whitelists a password param in the schema (checks the
:set_passwordpermission). -
#schema_wrapper_key_for(data) ⇒ Object
Attr reader for @schema_wrapper_key with auto-calculated default.
-
#skip_autofocus ⇒ void
protected
DSL method, skips adding autofocus to the first field.
-
#with_simpleform(simpleform, controller) ⇒ Object
This method is used by render to store the simpleform instance inside the component such that we can call methods from inside
form_fields.
Instance Method Summary collapse
-
#initialize(*args, cancancan_action: :missing, disabled: false, **kwargs) ⇒ Form
constructor
A new instance of Form.
Methods inherited from Compony::Component
#before_render, comp_name, #content, #exposed_intents, family_name, #id, #id_path, #id_path_hash, #inspect, #param_name, #path, #remove_content, #remove_content!, #render, #resourceful?, #root_comp, #root_comp?, setup, #sub_comp
Constructor Details
#initialize(*args, cancancan_action: :missing, disabled: false, **kwargs) ⇒ Form
Returns a new instance of Form.
6 7 8 9 10 11 |
# File 'lib/compony/components/form.rb', line 6 def initialize(*args, cancancan_action: :missing, disabled: false, **kwargs) @schema_lines_for_data = [] # Array of procs taking data returning a Schemacop proc @cancancan_action = cancancan_action @form_disabled = disabled super end |
Instance Method Details
#collect ⇒ Object
Quick access for wrapping collections in Rails compatible format
182 183 184 |
# File 'lib/compony/components/form.rb', line 182 def collect(...) Compony::ModelFields::Anchormodel.collect(...) end |
#disable! ⇒ void
This method returns an undefined value.
DSL method, disables all inputs.
189 190 191 |
# File 'lib/compony/components/form.rb', line 189 def disable! @form_disabled = true end |
#f ⇒ SimpleForm::FormBuilder
DSL method (inside form_fields). Returns the underlying simple_form builder, e.g. for f.rich_text_area
or f.simple_fields_for (nested attributes).
176 177 178 179 |
# File 'lib/compony/components/form.rb', line 176 def f fail("The `f` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform return @simpleform end |
#field(name, multilang: false, **input_opts) ⇒ String+
DSL method (inside form_fields). Renders a simple_form input inferred from the model field name.
Respects per-field CanCanCan authorization; skipped fields render nothing.
113 114 115 116 117 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 |
# File 'lib/compony/components/form.rb', line 113 def field(name, multilang: false, **input_opts) fail("The `field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform if multilang I18n.available_locales.map { |locale| field("#{name}_#{locale}", **input_opts) } else name = name.to_sym input_opts.merge!(disabled: true) if @form_disabled # Check per-field authorization if @cancancan_action.present? && @controller.current_ability.permitted_attributes(@cancancan_action, @simpleform.object).exclude?(name) Rails.logger.debug do "Skipping form field #{name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{@simpleform.object}." end return end hidden = input_opts.delete(:hidden) model_field = @simpleform.object.fields[name] fail("Field #{name.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field if hidden return model_field.simpleform_input_hidden(@simpleform, self, **input_opts) else unless @focus_given || @skip_autofocus input_opts[:autofocus] = true unless input_opts.key? :autofocus @focus_given = true end return model_field.simpleform_input(@simpleform, self, **input_opts) end end end |
#form_fields { ... } ⇒ Proc?
DSL method, use to set the form content (mandatory).
The block holds the form inputs and is instance-exec'd in the form's request context where field, pw_field and f are available.
62 63 64 65 |
# File 'lib/compony/components/form.rb', line 62 def form_fields(&block) return @form_fields unless block_given? @form_fields = block end |
#form_params(**new_form_params) ⇒ void
This method returns an undefined value.
DSL method, customizes the parameters given to simple_form_for.
197 198 199 |
# File 'lib/compony/components/form.rb', line 197 def form_params(**new_form_params) @form_params = new_form_params end |
#pw_field(name, **input_opts) ⇒ String?
DSL method (inside form_fields). Renders a password input; should be used for :password and :password_confirmation.
Checks the :set_password CanCanCan ability; :hidden is intentionally unsupported here.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/compony/components/form.rb', line 153 def pw_field(name, **input_opts) fail("The `pw_field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform name = name.to_sym # Check for authorization unless @cancancan_action.nil? || @controller.current_ability.can?(:set_password, @simpleform.object) Rails.logger.debug do "Skipping form pw_field #{name.inspect} because the current user is not allowed to perform :set_password on #{@simpleform.object}." end return end unless @focus_given || @skip_autofocus input_opts[:autofocus] = true unless input_opts.key? :autofocus @focus_given = true end return @simpleform.input name, **input_opts end |
#schema(wrapper_key) { ... } ⇒ void (protected)
This method returns an undefined value.
DSL method, replaces the form's schema and wrapper key with a completely manual Schemacop3 schema.
273 274 275 276 277 278 279 280 |
# File 'lib/compony/components/form.rb', line 273 def schema(wrapper_key, &block) if block_given? @schema_wrapper_key = wrapper_key @schema_block = block else fail 'schema requires a block to be given' end end |
#schema_block_for(data, controller) ⇒ Object
Attr reader for @schema_block with auto-calculated default
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/compony/components/form.rb', line 78 def schema_block_for(data, controller) if @schema_block return @schema_block else # If schema was not called, auto-infer a default local_schema_lines_for_data = @schema_lines_for_data return proc do local_schema_lines_for_data.each do |schema_line| schema_line_proc = schema_line.call(data, controller) # This may return nil, e.g. is the user is not authorized to set a field instance_exec(&schema_line_proc) unless schema_line_proc.nil? end end end end |
#schema_field(field_name, multilang: false) ⇒ void (protected)
This method returns an undefined value.
DSL method, whitelists a single field of data_class in the param schema, auto-generating the correct schema line.
Respects per-field CanCanCan authorization.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/compony/components/form.rb', line 221 def schema_field(field_name, multilang: false) if multilang I18n.available_locales.each { |locale| schema_field("#{field_name}_#{locale}") } else # This runs upon component setup. @schema_lines_for_data << proc do |data, controller| # This runs within a request context. field = data.class.fields[field_name.to_sym] || fail("No field #{field_name.to_sym.inspect} found for #{data.inspect} in #{inspect}.") # Check per-field authorization if @cancancan_action.present? && controller.current_ability.permitted_attributes(@cancancan_action.to_sym, data).exclude?(field.name.to_sym) Rails.logger.debug do "Skipping form schema_field #{field_name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{data}." end next nil end next field.schema_line end end end |
#schema_fields(*field_names) ⇒ void (protected)
This method returns an undefined value.
DSL method, whitelists several fields at once (see #schema_field).
264 265 266 |
# File 'lib/compony/components/form.rb', line 264 def schema_fields(*field_names) field_names.each { |field_name| schema_field(field_name) } end |
#schema_line { ... } ⇒ void (protected)
This method returns an undefined value.
DSL method, adds a Schemacop3 line whitelisting param(s) inside the schema's wrapper.
211 212 213 |
# File 'lib/compony/components/form.rb', line 211 def schema_line(&block) @schema_lines_for_data << proc { |_data, _controller| block } end |
#schema_pw_field(field_name) ⇒ void (protected)
This method returns an undefined value.
DSL method, whitelists a password param in the schema (checks the :set_password permission).
245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/compony/components/form.rb', line 245 def schema_pw_field(field_name) # This runs upon component setup. @schema_lines_for_data << proc do |data, controller| # This runs within a request context. # Check per-field authorization unless @cancancan_action.nil? || controller.current_ability.can?(:set_password, data) Rails.logger.debug do "Skipping form schema_pw_field #{field_name.inspect} because the current user is not allowed to perform :set_password on #{data}." end next nil end next proc { obj? field_name.to_sym } end end |
#schema_wrapper_key_for(data) ⇒ Object
Attr reader for @schema_wrapper_key with auto-calculated default
68 69 70 71 72 73 74 75 |
# File 'lib/compony/components/form.rb', line 68 def schema_wrapper_key_for(data) if @schema_wrapper_key.present? return @schema_wrapper_key else # If schema was not called, auto-infer a default data.model_name.singular end end |
#skip_autofocus ⇒ void (protected)
This method returns an undefined value.
DSL method, skips adding autofocus to the first field.
285 286 287 |
# File 'lib/compony/components/form.rb', line 285 def skip_autofocus @skip_autofocus = true end |
#with_simpleform(simpleform, controller) ⇒ Object
Refactor? Could this be greatly simplified by having form_field to |f| ?
This method is used by render to store the simpleform instance inside the component such that we can call
methods from inside form_fields. This is a workaround required because the form does not exist when the
RequestContext is being built, and we want the method field to be available inside the form_fields block.
97 98 99 100 101 102 103 104 |
# File 'lib/compony/components/form.rb', line 97 def with_simpleform(simpleform, controller) @simpleform = simpleform @controller = controller @focus_given = false yield @simpleform = nil @controller = nil end |