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
Instance Method Summary collapse
-
#collect ⇒ Object
Quick access for wrapping collections in Rails compatible format.
-
#disable! ⇒ Object
DSL method, disables all inputs.
-
#f ⇒ Object
Called inside the form_fields block.
-
#field(name, multilang: false, **input_opts) ⇒ Object
Called inside the form_fields block.
-
#form_fields(&block) ⇒ Object
DSL method, use to set the form content.
-
#form_params(**new_form_params) ⇒ Object
DSL method, allows to customize parameters given to simple_form_for.
-
#initialize(*args, cancancan_action: :missing, disabled: false, **kwargs) ⇒ Form
constructor
A new instance of Form.
-
#pw_field(name, **input_opts) ⇒ Object
Called inside the form_fields block.
-
#schema(wrapper_key, &block) ⇒ Object
protected
DSL method, use to replace the form's schema and wrapper key for a completely manual schema.
-
#schema_block_for(data, controller) ⇒ Object
Attr reader for @schema_block with auto-calculated default.
-
#schema_field(field_name, multilang: false) ⇒ Object
protected
DSL method, adds a new field to the schema whitelisting a single field of data_class This auto-generates the correct schema line for the field.
-
#schema_fields(*field_names) ⇒ Object
protected
DSL method, mass-assigns schema fields.
-
#schema_line(&block) ⇒ Object
protected
DSL method, adds a new line to the schema whitelisting a single param inside the schema's wrapper The block should be something like
str? :foo
and will run in a Schemacop3 context. -
#schema_pw_field(field_name) ⇒ Object
protected
DSL method, adds a new password field to the schema whitelisting This checks for the permission :set_password and auto-generates the correct schema line for the field.
-
#schema_wrapper_key_for(data) ⇒ Object
Attr reader for @schema_wrapper_key with auto-calculated default.
-
#skip_autofocus ⇒ Object
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
.
Methods inherited from Compony::Component
#action, #before_render, #comp_cst, comp_cst, comp_name, #comp_name, #content, family_cst, #family_cst, family_name, #family_name, #id, #inspect, #param_name, #path, #path_hash, #remove_content, #remove_content!, #render, #render_actions, #resourceful?, #root_comp, #root_comp?, setup, #skip_action, #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
164 165 166 |
# File 'lib/compony/components/form.rb', line 164 def collect(...) Compony::ModelFields::Anchormodel.collect(...) end |
#disable! ⇒ Object
DSL method, disables all inputs
169 170 171 |
# File 'lib/compony/components/form.rb', line 169 def disable! @form_disabled = true end |
#f ⇒ Object
Called inside the form_fields block. This makes the method f
available in the block.
See also notes for with_simpleform
.
158 159 160 161 |
# File 'lib/compony/components/form.rb', line 158 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) ⇒ Object
Called inside the form_fields block. This makes the method field
available in the block.
See also notes for with_simpleform
.
If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility"). Render the array as you wish.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/compony/components/form.rb', line 100 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(&block) ⇒ Object
DSL method, use to set the form content
53 54 55 56 |
# File 'lib/compony/components/form.rb', line 53 def form_fields(&block) return @form_fields unless block_given? @form_fields = block end |
#form_params(**new_form_params) ⇒ Object
DSL method, allows to customize parameters given to simple_form_for
174 175 176 |
# File 'lib/compony/components/form.rb', line 174 def form_params(**new_form_params) @form_params = new_form_params end |
#pw_field(name, **input_opts) ⇒ Object
Called inside the form_fields block. This makes the method pw_field available in the block. This method should be called for the fields :password and :password_confirmation Note that :hidden is not supported here, as this would make no sense in conjunction with :password or :password_confirmation.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/compony/components/form.rb', line 137 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, &block) ⇒ Object (protected)
DSL method, use to replace the form's schema and wrapper key for a completely manual schema
232 233 234 235 236 237 238 239 |
# File 'lib/compony/components/form.rb', line 232 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
69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/compony/components/form.rb', line 69 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) ⇒ Object (protected)
DSL method, adds a new field to the schema whitelisting a single field of data_class This auto-generates the correct schema line for the field. If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility")
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/compony/components/form.rb', line 189 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) ⇒ Object (protected)
DSL method, mass-assigns schema fields
227 228 229 |
# File 'lib/compony/components/form.rb', line 227 def schema_fields(*field_names) field_names.each { |field_name| schema_field(field_name) } end |
#schema_line(&block) ⇒ Object (protected)
DSL method, adds a new line to the schema whitelisting a single param inside the schema's wrapper
The block should be something like str? :foo
and will run in a Schemacop3 context.
182 183 184 |
# File 'lib/compony/components/form.rb', line 182 def schema_line(&block) @schema_lines_for_data << proc { |_data, _controller| block } end |
#schema_pw_field(field_name) ⇒ Object (protected)
DSL method, adds a new password field to the schema whitelisting This checks for the permission :set_password and auto-generates the correct schema line for the field.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/compony/components/form.rb', line 211 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
59 60 61 62 63 64 65 66 |
# File 'lib/compony/components/form.rb', line 59 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 ⇒ Object (protected)
DSL method, skips adding autofocus to the first field
242 243 244 |
# File 'lib/compony/components/form.rb', line 242 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.
88 89 90 91 92 93 94 95 |
# File 'lib/compony/components/form.rb', line 88 def with_simpleform(simpleform, controller) @simpleform = simpleform @controller = controller @focus_given = false yield @simpleform = nil @controller = nil end |