Module: CrudComponents::RouteResolver
- Defined in:
- lib/crud_components/route_resolver.rb
Overview
Resolves derived actions and record links to routes: the most specific conventional route first (association-scoped when the collection came from an association), then the top-level route, then nil — a nil means the button/link is omitted, never broken.
Class Method Summary collapse
- .action_path(view, action, record: nil, model: nil, owner: nil) ⇒ Object
-
.collection_index_path(view, target, owner, assoc_name) ⇒ Object
The index a has_many “+n more” link points at: 1.
- .collection_path(view, action, model, owner) ⇒ Object
-
.inverse_filter(target, owner, assoc_name) ⇒ Object
The target’s belongs_to that mirrors the owner’s collection (matched by foreign key), if it is filterable — with the owner’s identify_by value.
- .member_candidates(prefix, record, owner) ⇒ Object
- .member_path(view, action, record, owner) ⇒ Object
-
.record_path(view, record, owner: nil) ⇒ Object
The plain link to a record (label cells, association cells): show route, then edit.
- .safe_url(view, helper, *args, **kwargs) ⇒ Object
-
.show_path(view, record, owner: nil) ⇒ Object
Whether the record has a plain (show) route — feeds the “:show button only without a label link” rule.
- .try_helpers(view, candidates) ⇒ Object
Class Method Details
.action_path(view, action, record: nil, model: nil, owner: nil) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/crud_components/route_resolver.rb', line 9 def action_path(view, action, record: nil, model: nil, owner: nil) if action.path_block subject = record || model return view.instance_exec(subject, &action.path_block) end if action.collection? collection_path(view, action, model, owner) else member_path(view, action, record, owner) end end |
.collection_index_path(view, target, owner, assoc_name) ⇒ Object
The index a has_many “+n more” link points at:
1. the nested index under the owner (publisher_books_path(publisher)),
2. else the target's index filtered by the owner — but ONLY when the
target actually has a filterable belongs_to back to the owner
(publisher→books works; a habtm like author↔books does not, so we
do not emit a link that would silently show everything),
3. else nil (the renderer shows "+n more" as plain text).
‘assoc_name` is the owner’s reflection name (e.g. :books).
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/crud_components/route_resolver.rb', line 46 def collection_index_path(view, target, owner, assoc_name) return nil unless owner key = target.model_name.route_key owner_key = owner.model_name.singular_route_key nested = "#{owner_key}_#{key}_path" return safe_url(view, nested, owner) if view.respond_to?(nested) flat = "#{key}_path" return nil unless view.respond_to?(flat) filter = inverse_filter(target, owner, assoc_name) return nil unless filter safe_url(view, flat, **{ filter[:param] => filter[:value] }) end |
.collection_path(view, action, model, owner) ⇒ Object
93 94 95 96 97 98 99 100 |
# File 'lib/crud_components/route_resolver.rb', line 93 def collection_path(view, action, model, owner) prefix = action.name == :new ? 'new_' : "#{action.name}_" key = action.name == :new ? model.model_name.singular_route_key : model.model_name.route_key candidates = [] candidates << ["#{prefix}#{owner.model_name.singular_route_key}_#{key}_path", [owner]] if owner candidates << ["#{prefix}#{key}_path", []] try_helpers(view, candidates) end |
.inverse_filter(target, owner, assoc_name) ⇒ Object
The target’s belongs_to that mirrors the owner’s collection (matched by foreign key), if it is filterable — with the owner’s identify_by value.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/crud_components/route_resolver.rb', line 65 def inverse_filter(target, owner, assoc_name) owner_reflection = owner.class.reflect_on_association(assoc_name) return nil unless owner_reflection&.foreign_key fk = owner_reflection.foreign_key.to_s inverse = target.reflect_on_all_associations(:belongs_to).find { |r| r.foreign_key.to_s == fk } return nil unless inverse field = Structure.for(target).field(inverse.name) return nil unless field.filterable? identify = Structure.for(owner.class).identify_by { param: inverse.name, value: owner.public_send(identify) } rescue CrudComponents::DefinitionError nil end |
.member_candidates(prefix, record, owner) ⇒ Object
102 103 104 105 106 107 108 |
# File 'lib/crud_components/route_resolver.rb', line 102 def member_candidates(prefix, record, owner) key = record.model_name.singular_route_key candidates = [] candidates << ["#{prefix}#{owner.model_name.singular_route_key}_#{key}_path", [owner, record]] if owner candidates << ["#{prefix}#{key}_path", [record]] candidates end |
.member_path(view, action, record, owner) ⇒ Object
88 89 90 91 |
# File 'lib/crud_components/route_resolver.rb', line 88 def member_path(view, action, record, owner) prefix = { show: nil, destroy: nil, edit: 'edit_' }.fetch(action.name, "#{action.name}_") try_helpers(view, member_candidates(prefix, record, owner)) end |
.record_path(view, record, owner: nil) ⇒ Object
The plain link to a record (label cells, association cells): show route, then edit. Returns [path, kind] or nil.
24 25 26 27 28 29 30 |
# File 'lib/crud_components/route_resolver.rb', line 24 def record_path(view, record, owner: nil) path = try_helpers(view, member_candidates(nil, record, owner)) return [path, :show] if path path = try_helpers(view, member_candidates('edit_', record, owner)) path ? [path, :edit] : nil end |
.safe_url(view, helper, *args, **kwargs) ⇒ Object
82 83 84 85 86 |
# File 'lib/crud_components/route_resolver.rb', line 82 def safe_url(view, helper, *args, **kwargs) kwargs.empty? ? view.public_send(helper, *args) : view.public_send(helper, *args, **kwargs) rescue ActionController::UrlGenerationError, NoMethodError nil end |
.show_path(view, record, owner: nil) ⇒ Object
Whether the record has a plain (show) route — feeds the “:show button only without a label link” rule.
34 35 36 |
# File 'lib/crud_components/route_resolver.rb', line 34 def show_path(view, record, owner: nil) try_helpers(view, member_candidates(nil, record, owner)) end |
.try_helpers(view, candidates) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/crud_components/route_resolver.rb', line 110 def try_helpers(view, candidates) candidates.each do |helper, args| next unless view.respond_to?(helper) begin return view.public_send(helper, *args) rescue ActionController::UrlGenerationError, NoMethodError next end end nil end |