Class: CrudComponents::Fields::BelongsToField
- Defined in:
- lib/crud_components/fields/belongs_to_field.rb
Overview
belongs_to / has_one: nil-safe link via the target's label. The filter (belongs_to only) accepts both the target's identify_by value (what the select submits) and free text matched against the target's label — the name shown in the cell — one param, two OR-combined parameterized subqueries.
Constant Summary
Constants inherited from Base
CrudComponents::Fields::Base::NON_EDITABLE_COLUMNS
Instance Attribute Summary
Attributes inherited from Base
#facets, #model, #name, #options
Instance Method Summary collapse
- #apply_derived_filter(scope, value: nil) ⇒ Object
- #apply_sort(scope, dir) ⇒ Object
-
#default_editable? ⇒ Boolean
── forms ──────────────────────────────────────────────────────────── Assigned via the foreign key; the select submits real ids (forms are POST bodies, not shareable URLs — unlike the filter, which uses identify_by).
- #default_renderer ⇒ Object
-
#derived_filter_control ⇒ Object
select (a dropdown of all targets) below
select_limitrows, else free text. - #derived_filterable? ⇒ Boolean
-
#derived_sortable? ⇒ Boolean
Sortable by the column behind the target's label — the name shown in the cell — reached with a join.
-
#eager_load ⇒ Object
Load the association, nesting the target's identity_preloads (its label's own association deps) plus any per-column
preload:so the target's label never N+1s. - #filter_choices(_query = nil) ⇒ Object
- #form_choices ⇒ Object
- #form_control ⇒ Object
-
#group_model ⇒ Object
Picker grouping: a belongs_to/has_one column anchors its target's group (polymorphic has no single target, so it groups under its own model).
- #permit_param ⇒ Object
- #reflection ⇒ Object
-
#search_spec_entry ⇒ Object
Default ?q= reaches the target's label (the name shown in the cell).
- #target ⇒ Object
- #target_structure ⇒ Object
Methods inherited from Base
#apply_filter, #apply_filter_facet, #column, #custom_header?, #declared_preloads, #editable?, #editable_permitted?, #filter_control, #filter_facet, #filter_includes_null?, #filterable?, #form_partial, #group_label, #header, #header_actions, #human_name, #initialize, #nullable?, #permitted?, #picker_label, #range_filter?, #render_block, #renderer, #renderer_options, #sort_facet, #sortable?, #typed_filter, #value
Constructor Details
This class inherits a constructor from CrudComponents::Fields::Base
Instance Method Details
#apply_derived_filter(scope, value: nil) ⇒ Object
63 64 65 66 67 68 69 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 63 def apply_derived_filter(scope, value: nil, **) return scope unless value identified = scope.where(name => target.where(target_structure.identify_by => value)) searched = like_subquery(scope, value) searched ? identified.or(searched) : identified end |
#apply_sort(scope, dir) ⇒ Object
42 43 44 45 46 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 42 def apply_sort(scope, dir) return super if sort_facet scope.left_joins(name).reorder(target.arel_table[sort_column].public_send(dir)) end |
#default_editable? ⇒ Boolean
── forms ──────────────────────────────────────────────────────────── Assigned via the foreign key; the select submits real ids (forms are POST bodies, not shareable URLs — unlike the filter, which uses identify_by).
88 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 88 def default_editable? = reflection.belongs_to? && !reflection.polymorphic? |
#default_renderer ⇒ Object
9 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 9 def default_renderer = :association |
#derived_filter_control ⇒ Object
select (a dropdown of all targets) below select_limit rows, else free
text. Counted per render, not memoized: the field instance lives on the
process-cached Structure, so a memoized count would freeze at its boot-time
value and render the wrong control once the table grows past the limit.
One COUNT per filter-row render is negligible next to rendering the table.
53 54 55 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 53 def derived_filter_control target.count <= CrudComponents.config.select_limit ? :select : :text end |
#derived_filterable? ⇒ Boolean
33 34 35 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 33 def derived_filterable? reflection.belongs_to? && !reflection.polymorphic? end |
#derived_sortable? ⇒ Boolean
Sortable by the column behind the target's label — the name shown in the cell — reached with a join. A block label, or a label that isn't a real column, has no SQL ordering, so the column isn't sortable then.
40 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 40 def derived_sortable? = sort_column.present? |
#eager_load ⇒ Object
Load the association, nesting the target's identity_preloads (its label's
own association deps) plus any per-column preload: so the target's
label never N+1s. e.g. { order: %i[customer training] }.
A polymorphic belongs_to has no single target class, so we can't nest its
label's preloads — just preload the association itself (Rails groups it by
type); the cell still renders each record's label and links it at runtime.
77 78 79 80 81 82 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 77 def eager_load return [name] if reflection.polymorphic? nested = (target_structure.identity_preloads + declared_preloads).uniq [nested.empty? ? name : { name => nested }] end |
#filter_choices(_query = nil) ⇒ Object
57 58 59 60 61 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 57 def filter_choices(_query = nil) structure = target_structure target.all.map { |record| [structure.label_for(record).to_s, record.public_send(structure.identify_by)] } .sort_by(&:first) end |
#form_choices ⇒ Object
92 93 94 95 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 92 def form_choices structure = target_structure target.all.map { |record| [structure.label_for(record).to_s, record.id] }.sort_by(&:first) end |
#form_control ⇒ Object
89 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 89 def form_control = :belongs_to |
#group_model ⇒ Object
Picker grouping: a belongs_to/has_one column anchors its target's group (polymorphic has no single target, so it groups under its own model).
21 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 21 def group_model = reflection.polymorphic? ? model : target |
#permit_param ⇒ Object
90 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 90 def permit_param = reflection.foreign_key.to_sym |
#reflection ⇒ Object
11 12 13 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 11 def reflection @reflection ||= model.reflect_on_association(name) end |
#search_spec_entry ⇒ Object
Default ?q= reaches the target's label (the name shown in the cell). Skipped for polymorphic (no single target) or a block/columnless label.
29 30 31 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 29 def search_spec_entry name if !reflection.polymorphic? && target_structure.label_field_name end |
#target ⇒ Object
15 16 17 |
# File 'lib/crud_components/fields/belongs_to_field.rb', line 15 def target reflection.klass end |