Duplicate slug in different models

Describe the issue:

Hey!
Let’s say I have 2 models solution and feature. They offer a different set of blocks but both build pages with a url like client.com/slug (and not client.com/solution/slug).
So technically, it is possible to create a page in each model with the same slug.
When in SSR, there is no way to know which model to query from the slug. We can query both but if we get 2 results, we don’t know which one to display.

  • We could say it is poor CMS UX and that each model should have a different url prefix. I agree but I am working on a client’s website with a lot of pages and can’t change that easily.
  • Maybe this mistake should never leave the “dato” side. We could imagine having a “root level unique field slug” so that the CMS doesn’t allow saving a record if the slug is already in use even in another model. This might be a plugin? But I’m surprised it does not exist yet.
  • I am missing something? This feels weird to me, I have been working with Dato on a lot of different clients projects for 5+ years and don’t remember having this issue before.

This topic is similar: Unique URL across different models

Hi @maxime.binet,

One idea: Can you make another separate model like slug_list, and use that to manage your slugs? Just something like this:

  • The slug field is the slug you want to use on the website. It is required and unique.
  • The record_to_load field is a single-link field to either a solution or feature record. It is also required and unique.
  • Together, this should ensure that every slug links to only one record (of any type), and no record can have more than one slug.
  • Your frontend can just query the slug_list model to know which specific record to fetch.

It makes the query a tiny bit more complicated to set up, but hopefully not too bad, and it should help you more cleanly enforce this situation inside Dato?


As for the other topic/feature request for “unique field across all models”, it hasn’t gotten a lot of upvotes unfortunately (it’s not a very common request), so it’s not something we’ve worked on yet.

Yes, you can write a plugin to do that, but I think it would be a bit janky (in terms of editor experience, since it would have to query all possible models in your project and then return a custom error message if it finds one). Probably using the built-in relationship, like above, would be a bit cleaner.

Would that work for you?

Hey @roger, thanks for your very quick response!

Ok that’s a smart idea! Will keep that in mind.

Why do you think it is not such a common request? Maybe because the standard practice is to have 1 model for 1 “form of slug”.
ie:

  • 1 model for client.com/${slug}
  • 1 model for client.com/solution/${slug}
    and not
  • 2 models for client.com/${slug}

Hey @maxime.binet I’m Marcelo, Rogers colleague!
Another thing I wanted to mention is that most people that want a slug verification system on Dato do their own custom one with our plugin SDK with a private plugin. Since it is fairly easy to develop, and allows you to tailor the validation/slug formatting exact to the need of your specific routes, most companies end up going with the custom private plugin approach :slight_smile:

1 Like

Yeah, it’s just what @m.finamor said :slight_smile: Most of the time (as far as I’ve seen), slugs more or less mirror the folder structure on the frontend. Simpler customizations can use existing plugins like https://www.datocms.com/marketplace/plugins/i/datocms-plugin-tree-like-slugs or https://www.datocms.com/marketplace/plugins/i/datocms-plugin-advanced-slug-prefix. For more complex systems, customers end up writing their own simple plugins… we can’t really do that for them because it totally depends on their business needs and frontend routing setup (we’re happy to help with plugin prototyping or debugging, though).

A more general “global unique” validation would still be difficult, because that’s not something databases generally support… we’d have to manually look up all the possible slug fields in all the possible models of your project and query them separately. Models can have more than one slug, and blocks can have their own slug fields. It turns the problem from a trivial “unique validation within this field” (which databases natively support) into a computationally expensive “unique across every slug field every record in this project and every nested block in each of those records” (a bunch of queries and indexing, and probably fragile). It’s also a difficult UI/UX problem because we don’t know which of all the possible slug fields are “related” to the one you’re trying to test uniqueness on, so you’d end up having to manually define a slug-to-slug cross-model relationship anyway, just in a more confusing way =/

When you manually define a relationship like in my example, however, then it’s much easier on the system because it just uses normal database systems (check if this one field is unique, and then find me the related record).

By the way, I should mention that if you do choose to use that workaround, you can use inverse relationships to easily look up the contents of the related solution or feature record inside the same query!