Class: CafeCar::Filter::FormBuilder
- Inherits:
-
Object
- Object
- CafeCar::Filter::FormBuilder
- Defined in:
- lib/cafe_car/filter/form_builder.rb
Class Method Summary collapse
-
.dotted_name(method) ⇒ Object
Rewrites a control's name to its bare dot-query key —
pricestaysprice, operators compose asprice.min— instead of the edit form'smodel[price]nesting, so a submitted control IS a filter param (Controller::Filtering treats every non-control index param as a filter).
Instance Method Summary collapse
- #clean(method) ⇒ Object
- #collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) ⇒ Object
- #field_name(*methods) ⇒ Object
-
#filter(method, **opts) ⇒ Object
The typed control for one permitted filter: the
_<type>_filterpartial (host-overridable per type),_range_filterfor the min/max family, then the generic_filterfallback. -
#info(method) ⇒ Object
Filter fields reflect through Filter::FieldInfo (the typed filter control mapping), keyed on the cleaned name so
name~andnameshare one info. -
#label(method, text = nil, **opts) ⇒ Object
A filter is always optional — no required-* marker on its label.
- #model ⇒ Object
-
#remaining_attributes ⇒ Object
The policy's permitted_filters — the panel's enumeration source — minus what the view already rendered and the types no control can express.
-
#scope_toggle(scope) ⇒ Object
A checkbox that turns a permitted model scope on (
?published=true). - #scopes ⇒ Object
-
#select(method, choices = nil, options = {}, html_options = {}, &block) ⇒ Object
The select family takes (options, html_options) hash pairs positionally, so the name rewrite rides in html_options (an explicit :name still wins).
Class Method Details
.dotted_name(method) ⇒ Object
Rewrites a control's name to its bare dot-query key — price stays
price, operators compose as price.min — instead of the edit form's
model[price] nesting, so a submitted control IS a filter param
(Controller::Filtering treats every non-control index param as a filter).
7 8 9 10 11 |
# File 'lib/cafe_car/filter/form_builder.rb', line 7 def self.dotted_name(method) define_method method do |key, *args, **opts, &block| super(key, *args, name: field_name(key), **opts, &block) end end |
Instance Method Details
#clean(method) ⇒ Object
32 |
# File 'lib/cafe_car/filter/form_builder.rb', line 32 def clean(method) = method.to_s.sub(/^\W+|\W+$/, "") |
#collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) ⇒ Object
21 22 23 24 25 26 27 28 |
# File 'lib/cafe_car/filter/form_builder.rb', line 21 def collection_select(method, collection, value_method, text_method, = {}, = {}) # A multi-select posts a set (`author_id[]`). We name every filter control # explicitly, which defeats Rails' automatic `[]` suffix, so restore it here. name = field_name(clean(method)) name += "[]" if [:multiple] super(method, collection, value_method, text_method, , { name: }.merge()) end |
#field_name(*methods) ⇒ Object
33 |
# File 'lib/cafe_car/filter/form_builder.rb', line 33 def field_name(*methods) = methods.join(".") |
#filter(method, **opts) ⇒ Object
The typed control for one permitted filter: the _<type>_filter partial
(host-overridable per type), _range_filter for the min/max family, then
the generic _filter fallback.
59 60 61 62 63 64 |
# File 'lib/cafe_car/filter/form_builder.rb', line 59 def filter(method, **opts) info = info(method) partial = [ "#{info.type}_filter", ("range_filter" if info.range?), "filter" ] .compact.find { @template.partial?(_1) } @template.render(partial, f: self, info:, **opts) end |
#info(method) ⇒ Object
Filter fields reflect through Filter::FieldInfo (the typed filter control
mapping), keyed on the cleaned name so name~ and name share one info.
37 38 39 40 |
# File 'lib/cafe_car/filter/form_builder.rb', line 37 def info(method) @infos ||= {} @infos[clean(method)] ||= const(:FieldInfo).new(model:, method: clean(method)) end |
#label(method, text = nil, **opts) ⇒ Object
A filter is always optional — no required-* marker on its label.
51 52 53 54 |
# File 'lib/cafe_car/filter/form_builder.rb', line 51 def label(method, text = nil, **opts, &) opts[:class] = [ ui.class(%i[field label]), *opts[:class] ] super(method, *text, required: false, **opts, &) end |
#model ⇒ Object
30 |
# File 'lib/cafe_car/filter/form_builder.rb', line 30 def model = object.model |
#remaining_attributes ⇒ Object
The policy's permitted_filters — the panel's enumeration source — minus what the view already rendered and the types no control can express.
44 45 46 |
# File 'lib/cafe_car/filter/form_builder.rb', line 44 def remaining_attributes policy.attributes.filterable.reject { info(_1).unfilterable? } - @fields.keys end |
#scope_toggle(scope) ⇒ Object
A checkbox that turns a permitted model scope on (?published=true).
67 68 69 |
# File 'lib/cafe_car/filter/form_builder.rb', line 67 def scope_toggle(scope) @template.render("scope_filter", f: self, scope:) end |
#scopes ⇒ Object
48 |
# File 'lib/cafe_car/filter/form_builder.rb', line 48 def scopes = policy.permitted_scopes |
#select(method, choices = nil, options = {}, html_options = {}, &block) ⇒ Object
The select family takes (options, html_options) hash pairs positionally, so the name rewrite rides in html_options (an explicit :name still wins).
17 18 19 |
# File 'lib/cafe_car/filter/form_builder.rb', line 17 def select(method, choices = nil, = {}, = {}, &block) super(method, choices, , { name: field_name(clean(method)) }.merge(), &block) end |