When turning a class into a reusable module, I needed to use some routing paths without knowing beforehand what the models were called. I wanted to write things like
new_category_path without knowing about
category; I needed a model-agnostic way to express routes. It turns out that Rails has this covered with Polymorphic Routes.
Take the route to create a new object, say a
Category, which would normally be expressed as:
new_category_path #=> "/en-GB/categories/new"
Now, assuming that
category is known as the variable
model, you can do
new_polymorphic_path(model) #=> "en-GB/categories/new"
model variable can contain the constant
Category, the string
category, or the symbol
:category. It can also be a model instance, for example:
edit_category_path(model) #=> "/en-GB/categories/1/edit"
can be written as
edit_polymorphic_path(model) #=> "/en-GB/categories/1/edit"
You can also make the action polymorphic: the above example can also be written
polymorphic_path([:edit, model]) #=> "/en-GB/categories/1/edit"
Note, however, how the arguments are presented as an array. An array is also used for nested routes. Instead of
new_category_category_path(model) #=> "/en-GB/categories/1/categories/new"
you can write
new_polymorphic_path([model,model.class]) #=> "/en-GB/categories/1/categories/new"
However, for a custom route like
index_category_path(model) #=> "/en-GB/categories/1/index"
index_polymorphic_path form doesn't work, but you can write
polymorphic_path([:index, model]) #=> "/en-GB/categories/1/index"
So it turns out to be very easy to write model-agnostic routes.
All of the above applies to URLs too: just replace
polymorphic_url([:edit, model]) #=> "http://localhost:3000/en-GB/categories/1/edit"