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