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.
-
#f ⇒ Object
Called inside the form_fields block.
-
#field(name, **input_opts) ⇒ Object
Called inside the form_fields block.
-
#form_fields(&block) ⇒ Object
DSL method, use to set the form content.
-
#initialize(*args, cancancan_action: :missing, **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) ⇒ 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, **kwargs) ⇒ Form
Returns a new instance of Form.
6 7 8 9 10 |
# File 'lib/compony/components/form.rb', line 6 def initialize(*args, cancancan_action: :missing, **kwargs) @schema_lines_for_data = [] # Array of procs taking data returning a Schemacop proc @cancancan_action = cancancan_action super end |
Instance Method Details
#collect ⇒ Object
Quick access for wrapping collections in Rails compatible format
154 155 156 |
# File 'lib/compony/components/form.rb', line 154 def collect(...) Compony::ModelFields::Anchormodel.collect(...) end |
#f ⇒ Object
Called inside the form_fields block. This makes the method f
available in the block.
See also notes for with_simpleform
.
148 149 150 151 |
# File 'lib/compony/components/form.rb', line 148 def f fail("The `f` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform return @simpleform end |
#field(name, **input_opts) ⇒ Object
Called inside the form_fields block. This makes the method field
available in the block.
See also notes for with_simpleform
.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/compony/components/form.rb', line 97 def field(name, **input_opts) fail("The `field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform name = name.to_sym # 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 |
#form_fields(&block) ⇒ Object
DSL method, use to set the form content
51 52 53 54 |
# File 'lib/compony/components/form.rb', line 51 def form_fields(&block) return @form_fields unless block_given? @form_fields = block 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.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/compony/components/form.rb', line 127 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
207 208 209 210 211 212 213 214 |
# File 'lib/compony/components/form.rb', line 207 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
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/compony/components/form.rb', line 67 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) ⇒ 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.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/compony/components/form.rb', line 168 def schema_field(field_name) # 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 |
#schema_fields(*field_names) ⇒ Object (protected)
DSL method, mass-assigns schema fields
202 203 204 |
# File 'lib/compony/components/form.rb', line 202 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.
162 163 164 |
# File 'lib/compony/components/form.rb', line 162 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.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/compony/components/form.rb', line 186 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 #{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
57 58 59 60 61 62 63 64 |
# File 'lib/compony/components/form.rb', line 57 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
217 218 219 |
# File 'lib/compony/components/form.rb', line 217 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.
86 87 88 89 90 91 92 93 |
# File 'lib/compony/components/form.rb', line 86 def with_simpleform(simpleform, controller) @simpleform = simpleform @controller = controller @focus_given = false yield @simpleform = nil @controller = nil end |