There is a good solution to this problem using route restrictions.
Using route restrictions
As shown in the rail routing guide , you can define route restrictions so that they check if the path belongs to a language or category.
# config/routes.rb
Order determines priority. In the above example, if the language and category have the same name, the language wins, since its route is defined above the route of the category.
Using the Permalink Model
If you want to make sure that all paths are uniqe, an easy way is to define the Permalink model and use validation there.
Create a database table: rails generate model Permalink path:string reference_type:string reference_id:integer && rails db:migrate
And define the validation in the model:
class Permalink < ApplicationRecord belongs_to :reference, polymorphic: true validates :path, presence: true, uniqueness: true end
And map it to other types of objects:
class Language < ApplicationRecord has_many :permalinks, as: :reference, dependent: :destroy end
It also allows you to define several permalink paths for writing.
rails_category.permalinks.create path: 'rails' rails_category.permalinks.create path: 'ruby-on-rails'
With this solution, the route file should look like this:
# config/routes.rb
And as a note for other users using the cancan stone and load_and_authorize_resource in the controller: you must load the entry at the permalink link before calling load_and_authorize_resource :
class Category < ApplicationRecord before_action :find_resource_by_permalink, only: :show load_and_authorize_resource private def find_resource_by_permalink @category ||= Permalink.find_by(path: params[:category]).try(:reference) end end