Add wildcard urls - a proposal#3776
Conversation
e835077 to
7b1fdcb
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3776 +/- ##
==========================================
+ Coverage 98.06% 98.08% +0.02%
==========================================
Files 322 324 +2
Lines 8526 8635 +109
==========================================
+ Hits 8361 8470 +109
Misses 165 165 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f7b0ca1 to
1846784
Compare
1846784 to
67f57ac
Compare
3039bfa to
dfb07d3
Compare
|
I adjusted the whole structure on this PR and updated the page defintion to use |
060ea55 to
c0a7f60
Compare
644b03a to
ef93e91
Compare
There are already format for email, url, and link_url, but the spec was missing.
Add the configuration for integer and uuid to format matchers. These option will be used for the wildcard url validation.
ef93e91 to
dbb9ae9
Compare
|
I renamed the service to |
dbb9ae9 to
22ebb5c
Compare
|
Two suggestions for Single-query optimization for Instead of walking the tree level by level (one query per depth level), we could avoid the N+1 with a single query approach:
candidates = Current.language.pages.contentpages.where("urlname LIKE ?", "%:%")
input_segments = urlname.split("/") # ["products", "42", "comments"]
candidates.find do |candidate|
pattern_segments = candidate.urlname.split("/") # ["products", ":id", "comments"]
next unless input_segments.size == pattern_segments.size
# match static segments exactly, extract params from wildcard segments
endSince urlnames are stored with wildcard patterns literally (e.g., For ambiguous matches (multiple candidates with same segment count), we'd need explicit priority — e.g., prefer the most specific match (most static segments). But that's solvable. Validate constraint types in Currently if value.is_a?(Hash) && value[:params].is_a?(Hash)
value[:params].each_value do |constraint|
next unless constraint.is_a?(String)
unless Alchemy.config.format_matchers.respond_to?(constraint.to_sym)
raise ArgumentError, "Unknown format matcher: #{constraint.inspect}"
end
end
endThat way typos blow up at YAML load time, not silently at request time. |
| # Returns the urlname of the page. | ||
| # If the page has a wildcard_url, you can pass params to substitute | ||
| # the wildcards in the urlname: page.urlname(id: 42) # => "products/42" | ||
| def urlname(**params) |
There was a problem hiding this comment.
I would prefer to handle this in url_path instead.
Add an active record type for wildcard urls. These types will be later used in the page definition and can a simple string or hash with a pattern attribute and an optional params attribute. This way the user can configure the wildcard for a page layout and it will be validated when Alchemy reads in the page layout.
Add a new attribute to page definition to allow the usage of wildcard_urls (e.g. :user_id/profile). They can have different configurations (simple string or a hash structure). Add also more page layouts to the dummy to test the different configuration later.
Prevent the creation of multiple pages with the same wildcard_url under the same parent page. Alchemy will validate the slug and will prevent creating the same slug twice. Also delegate the wildcard_url to the page delegation.
Add a new service which find the page by urlname or should try to find the correct wildcard url for a given parent_page. It will traverse the page tree and will try to match all page_layouts with a wildcard_url. The first match wins and will be returned. The page and params are stored in the service itself and can be received later in the controller.
Use the page finder service object to find the page per urlname or try to find a page with wildcard_url. The params will be extended by the page finder service, if a wildcard url is used.
It wouldn't work to update the slug anyway, because the urlname mechanic is different for pages with a wildcard_url. The slug form field will be disabled and the slug can also contain slashes.
44808a1 to
d24f9d4
Compare
|
|
||
| format_matchers = Alchemy.config.format_matchers | ||
| if format_matchers.respond_to?(constraint.to_sym) | ||
| strip_anchors(format_matchers.public_send(constraint.to_sym).source) |
Allow the setting of wildcard parameter in url_path class. It is using the already given optional_params attribute to add parameter to the wildcard url.
To ease the complexity of the page_finder it is required, that the parameter key is unique for all page layouts. This requirement is reducing the searching complexity and also prevent edge cases where different page_layouts in the same tree can have multiple times the same parameter name (e.g. :id). ^ Conflicts: ^ spec/models/alchemy/page_spec.rb
d24f9d4 to
cee199b
Compare
What is this pull request for?
Add a possibility to create wildcard pages. A page layout can now have a wildcard_url (e.g. ":awesome_id"). With that in place it is possible to create dynamic pages.
This PR is only the technical groundwork. It does not handle admin view changes. It would be preferable to prevent changing the slug in the page information modal and it would be helpful for the user to see a hint in the page tree, if a page contains wildcards.
Screenshots
Page Layout Configuration
A resolved URL
View Template
Page Sitemap
Page Properties
Checklist