Is there any way to pass route constraints to a Rails::Engine route?

Hey folks - I’m spinning up a new app on Rails 8 and have run into a new issue. For this app, I’m using a database source that’s out of my control that uses non-standard primary keys. Some of these keys use periods/dots in the ID, which is not supported by the default Rails router parameter parsing. The guides suggest a work-around using constraints, eg. resources :articles, constraints: { id: /[^\/]+/ }, which works great in my applications routes.

Where I’ve run into a snag is that I’m also using Avo for my admin panel (it’s fantastic, BTW!). Unfortunately, it doesn’t appear that I can pass the id constraint down to the rails engine, which breaks restful routing in Avo because there’s no way to tell it to allow periods in the id param from what I can tell…I’ve also created a simple reproduction of the issue by creating a simple rails engine that exposes a route with and id param. When I go to a route where the id contains a dot, the param gets truncated.

I’ve scoured the internet and I can’t seem to find any questions or articles related to this issue (specifically when it comes to applying constraints to routes within a mounted engine). Curious if anyone else has run into this issue and if there’s a possible fix?

For now, I’m just working around the issue with some ID transformation hackery (subbing the dots with underscores), but it feels like it could be brittle (i.e. in the case where an id has both dots and underscores in the ID key).

Thanks!

Have you tried using signed_id instead of just id? Not sure how it handles your PKs, but it’s a rails provided way to generate an id that is ASCII from the real id.

Thanks for the suggestion - always love when I learn some new hidden bit of Rails functionality!

I took a look and it appears it would work for interacting with a single resource…unfortunately, I don’t see any notes about how to use it with a group of records (e.g. there’s no `where(signed_id:), which needs to be supported by the engine, so it’s probably not a viable solution for this case…any thoughts for that case?

There is a find_signed method

That takes a single value at a time - but creating your own method to iterate over a collection, could bring you the functionality you need.

  1. Pass a group of signed ids
  2. Calculate them to a group of database ids by using the verifier
  3. Create use the values to create a single where(..) call