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? :fooand 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
#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
170 171 172 |
# File 'lib/compony/components/form.rb', line 170 def collect(...) Compony::ModelFields::Anchormodel.collect(...) end |
#disable! ⇒ Object
DSL method, disables all inputs
175 176 177 |
# File 'lib/compony/components/form.rb', line 175 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.
164 165 166 167 |
# File 'lib/compony/components/form.rb', line 164 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.
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 133 134 135 136 137 138 |
# File 'lib/compony/components/form.rb', line 106 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
59 60 61 62 |
# File 'lib/compony/components/form.rb', line 59 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
180 181 182 |
# File 'lib/compony/components/form.rb', line 180 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.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/compony/components/form.rb', line 143 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
238 239 240 241 242 243 244 245 |
# File 'lib/compony/components/form.rb', line 238 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
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/compony/components/form.rb', line 75 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")
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/compony/components/form.rb', line 195 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
233 234 235 |
# File 'lib/compony/components/form.rb', line 233 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.
188 189 190 |
# File 'lib/compony/components/form.rb', line 188 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.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/compony/components/form.rb', line 217 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
65 66 67 68 69 70 71 72 |
# File 'lib/compony/components/form.rb', line 65 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
248 249 250 |
# File 'lib/compony/components/form.rb', line 248 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.
94 95 96 97 98 99 100 101 |
# File 'lib/compony/components/form.rb', line 94 def with_simpleform(simpleform, controller) @simpleform = simpleform @controller = controller @focus_given = false yield @simpleform = nil @controller = nil end |