I have got a simple issue where I have 2 routes which do different things, one is:
blah\groups\:group_id
and then
blah\groups\count
Now the first returns a specific group, the latter returns the amount of groups the user has access to. Now the problem is that the first route is hit even when I use the 2nd route url. Which makes sense as it doesnt know that there is a different route for count. I was looking at doing regex to tell it to use group_id if it does not contain count however then I cannot use the router.param with it, so is there a way to tell express to use count first then if that isnt matched try the group_id one? or if not any way to keep the parameter name but attach some regex so it has the context of what to look for but retains the parameter name?
Routes work like middleware and are executed in the order they are placed.
Having blah\groups\count before blah\groups\:group_id will make sure a match of count comes before :group_id.
Related
I am working with the Google Ads team in my company on a Shopify store and they asked me for some regular expressions for the several steps of the checkout process. I created them and everything was running fine, until the guys noticed that sometimes Analytics added a _ga paremeter to the URL query parameters.
My original expressions are:
1. When in cart - no problem here
\/cart
2. First step of checkout - Contact Information - In several lines for easier reading
(
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)$
|
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)\?step=contact_information
)
In this part I added the step=contact_information as an OR option. It isn't normally there except for when you go back to contact information it is added to the URL as step. I know this is not the ideal way, but I am far from fluent in regex.
3. Shipping information
(
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)\?step=shipping_method
|
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)?(.*)&step=shipping_method
)
In this part it always has step=shipping_method but it can also have previous_step=contact_information. This is also not ideal, but I am not sure how to do it.
4. Payment information
(
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)\?step=payment_method
|
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)?(.*)&step=payment_method
)
The same as step 3, in this case it always has step=payment_method but it can also have previous_step=shipping_method. As points 2 and 3, not ideal.
5. Processing - this part works fine, because I am not interested in the query parameters
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)\/processing
6. Thank you page - this also works fine, because I am not interested in the query parameters
\/([0-9]*)\/checkouts\/([a-z0-9\-]*)\/thank_you
Issue with _ga parameter
Those regular expressions work fine with the regular URLs, but when I add the _ga parameter to the URL they don't match. I think there was a way to match query parameters, but I am not sure how to match certain and exclude others.
The _ga parameter normally persists on the next steps
The list of all the possible matches for points 2., 3. and 4.:
Contact information without and with _ga
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?step=contact_information
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es&step=contact_information
Shipping method without and with _ga
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?step=shipping_method
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?step=shipping_method&previous_step=contact_information
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es&step=shipping_method
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es&step=shipping_method&previous_step=contact_information
Payment method without and with _ga
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?step=payment_method
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?step=payment_method&previous_step=shipping_method
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es&step=payment_method
/25931284564/checkouts/df24e48ecc81f767583c4a26680bcb82?_ga=2.150710640.738515769.1576779089-71346777.1571176760%26_gac%3D1.16451458.1576260301.EAIaIQobChMI9v2c5Zqz5gIVr__jBx1VAgxPEAAYBCAAEgLccPD_BwE&locale=es&step=payment_method&previous_step=shipping_method
Any ideas how I could solve this? I am pretty sure it's simple, but my brain just doesn't get around more complex regular expressions :)
UPDATE
Just to clear this up a bit more, what I need to achieve with the regular expressions is to identify specifically the step of the funnel.
The Google Ads guys from my team are creating a funnel in Analytics and they add the corresponding steps from the checkout as stages of the funnel.
So basically I just need my regexes to be able to work with or without the _ga query, BUT always detecting a specific step.
UPDATE 2
I added all the possible matches. I need to be able to identify the specific step through the regular expression. So basically I need one regular expression for contact information, one for shipping method and one for payment method, each identifying only the specific step with or without _ga in the URL.
I believe for the checkout url you can simply use this regex:
/([0-9]+)/checkouts/([a-z0-9-]+)(?:.*step=([a-z0-9_-]+))?
no matter if the url is with/without _ga parameter.
Basically it will provide you three groups in a match, the third group will contain step parameter value, e.g.: contact_information
Example:
https://regex101.com/r/C1GuDY/1
I am working on a coldbox application where I would like to create a route that accepts 'n' number of path variables as one variable. Here is what I mean.
http://localhost/api/variable1/variable2/variable3/...
I would like to either be able to grab everything after /api as one path variable where I can split on / and get the values or be able to iterate over all variables after /api.
Is there a way to setup a Route to do this?
with(pattern="/api", handler="api")
.addRoute(pattern="/:variables", action="index")
.endWith();
Any ideas would be most appreciated. Thanks in advance.
As you probably know, the default routing paradigm is to do name value pairs like so:
http://localhost/api/name1/value1/name2/value2/name3/value3
There is no need to create a custom route for that as everything after the matched part of the route is broken up into name/value pairs and placed in the rc automatically.
Now, it sounds like you're wanting to only have values in your route. If you know the maximum number of variables you'll ever have, you could create a route of optional, incrementally-named variables.
addRoute(pattern="/:var1?/:var2?/:var3?/:var4?/:var5?", action="index")
Now, if you truly might have an unlimited number of variables, there is no way to do a route that will match that. What you CAN do is have your route match the /api bit and write an onRequestCapture interceptor that grabs the URL and does your own custom parsing on it. Note, you may need to remove the name/value pairs that ColdBox will try to put in the rc.
I will add a note of caution-- the only way for this to really work is for you to KNOW the order of the incoming variables ahead of time, and if you know that, there is no reason why you can't create a known route for it. Otherwise you're basically rebuilding the SES interceptor over again which is an anti-pattern called "inner platform effect"
http://wiki.coldbox.org/wiki/URLMappings.cfm#URL_Mappings
http://wiki.coldbox.org/wiki/Interceptors.cfm#Core_Interception_Points
http://en.wikipedia.org/wiki/Inner-platform_effect
I need to write a CI route so that it loads the right controller. What I want to do is write a route that excludes the "features" controller. Here are my routes (but the first one doesn't work).
$route['(\w{2})/(\w{2})/products/([\w]+!features)'] = "products/products/$3"; // folder/controller/method
$route['(\w{2})/(\w{2})/products/features/([\w]+)'] = "products/features/$3"; // folder/controller/method
What I want to have happen is the top line should load any controller that is not the features controller. But I am getting conflicts between the two lines. I've tried placing the "!features" in a couple of different places in the line, with and without quotes and I'm still getting either the features controller to load or one of the other methods in the products controller to load. But not both. Can someone help out here? Thanks.
Try changing the first line to:
$route['(\w{2})/(\w{2})/products/(?!features$)(\w+)'] = "products/products/$3";
(?!foo) is a negative lookahead, if fails if whatever is following it matches foo.
$ means end of string, and is there to make sure that features is not part of a longer word.
I have a route defined as follows:
(r'^edit/(\d+)/$', 'app.path.edit')
I want to use the reverse function as follows:
url = reverse('app.path.edit', args=('-id-',))
The generated url gets passed to a js function, and client side code will eventually replace '-id-' with the correct numeric id. This of course won't work, because the 'reverse' function won't match the route, because the url is defined as containing a numeric argument.
I can change the route to accept any type of argument as follows, but then I loose some specificity:
(r'^edit/(.+)/$', 'app.path.edit'
I could create a separate url for each item being displayed, but I'll be displaying many items in a list, so it seems like a waste of bandwidth to include the full url for each item.
Is there a better strategy to accomplish what I want to do?
You can rewrite regexp like this:
(r'^edit/(\d+|-id-)/$', 'app.path.edit')
but I generally prefer this:
(r'^edit/([^/]+)/$', 'app.path.edit') # you can still differ "edit/11/" and "edit/11/param/"
Usually you will anyway need to check entity for existent with get_object_or_404 shortcut or similar, so the only bad is that you have to be more accurate with incoming data as id can contain almost any characters.
In my opinion, and easier solution would be to keep the original url and then pass the value '0' instead of '-id-'. In the client side then you replace '/0/' with the correct id. I think this is better because it doesn't obscure the url routing, and you don't lose specificity.
Say I request
parent/child/child/page-name
in my browser. I want to extract the parent, children as well as page name. Here are the regular expressions I am currently using. There should be no limit as to how many children there are in the url request. For the time being, the page name will always be at the end and never be omitted.
^([\w-]{1,}){1} -> Match parent (returns 'parent')
(/(?:(?!/).)*[a-z]){1,}/ -> Match children (returns /child/child/)
[\w-]{1,}(?!.*[\w-]{1,}) -> Match page name (returns 'page-name')
The more I play with this, the more I feel how clunky this solution is. This is for a small CMS I am developing in ASP Classic (:(). It is sort of like the MVC routing paths. But instead of calling controllers and functions based on the URL request. I would be travelling down the hierarchy and finding the appropriate page in the database. The database is using the nested set model and is linked by a unique page name for each child.
I have tried using the split function to split with a / delimiter however I found I was nested so many split statements together it became very unreadable.
All said, I need an efficient way to parse out the parent, children as well as page name from a string. Could someone please provide an alternative solution?
To be honest, I'm not even sure if a regular expression is the best solution to my problem.
Thank you.
You could try using:
^([\w-]+)(/.*/)([\w-]+)$
And then access the three matching groups created using Match.SubMatches. See here for more details.
EDIT
Actually, assuming that you know that [\w-] is all that is used in the names of the parts, you can use ^([\w-]+)(.*)([\w-]+)$ instead and it will handle the no-child case fine by itself as well.