Refining Scrivito's Routing

Scrivito lets you customize the URLs under which your pages are available. Watch this introduction to Scrivito's routing.

Using the slug method, you can adapt the URL format to your needs. However, if you'd like Scrivito to deliver only a particular section of your website, you require full control over the routing Scrivito adds to your application. This is made possible through the scrivito_route API.

Prior to refining the routing of your application, the default routes Scrivito injects into your application need to be disabled. To do this, set the inject_preset_routes configuration to false. If you started from scratch, the “install” generator has already done this for you.

Scrivito.configure do |config|
  config.inject_preset_routes = false
end

Without the default routes, Scrivito cannot determine the URLs of CMS objects. You can fix this by using the scrivito_route API. To reproduce the familiar Scrivito routing, append the following three lines to your config/routes.rb file:

  scrivito_route '/', using: 'homepage', via: :all
  scrivito_route '(/)(*slug-):id', using: 'slug_id', via: :all
  scrivito_route '/*permalink', using: 'permalink', format: false, via: :all

The first parameter to scrivito_route is a Rails routing pattern. The only required option is using. It specifies the kind of objects the given route should be used for. For example, using: "permalink" instructs Scrivito to use the route for CMS objects whose _permalink attribute has been set. The valid values for using are homepage, permalink, and slug_id. Note that permalink and slug_id expect dynamic route segements to be included in the routing pattern. See the API documentation for further details.

In additon to the using option, the via and format options can be specified. The effect of these options is similar to that of the equally named Rails routing options: via lets you specify the HTTP verbs to which the route is applicable. In the example above, the special :all value is used to match all HTTP verbs. The format option, finally, allows you to match URLs despite their format suffix (e.g. “.json”). Set this option to true to enable this behavior.

Adapting Scrivito routes

Of course, we recommend using Scrivito for all sections of your website. However, if you want to use it for a specific website part only, e.g. your blog, that's pretty easy. Just replace the default routes with:

  scrivito_route '/blog', using: 'homepage', via: :all
  scrivito_route '/blog/(*slug-):id', using: 'slug_id', via: :all
  scrivito_route '/blog/*permalink', using: 'permalink', format: false, via: :all

This causes Scrivito to be responsible for the “/blog” section of your site only. You can even combine the Scrivito routes with Rails helpers:

  scope :blog do
    scrivito_route '/', using: 'homepage', via: :all
    scrivito_route '(/)(*slug-):id', using: 'slug_id', via: :all
    scrivito_route '/*permalink', using: 'permalink', format: false, via: :all
  end

Redirecting URLs matching old schemes

When changing your routing, you should be aware of the fact that there may be several URLs circulating that won't work with your new routing schemes. Such URLs might have been cached by search engines or included in a mailing that was sent out some time ago.

For example, changing Scrivito's default ID-last routing to an ID-first routing would cause an old ID-last URL such as my-slug-f91446e492be2ab1 to not be matched anymore and thus produce a 404 page. Including a redirect prevents this without impacting the new routing:

scrivito_route '/', using: 'homepage', via: :all
scrivito_route '(/):id(/*slug)', using: 'slug_id', via: :all
get '/*slug-:id', to: redirect('/%{id}/%{slug}'), constraints: {id: /\h{16}/}

scrivito_route '/*permalink', using: 'permalink', format: false, via: :all

Note that the definition of the redirect precedes the permalink route. This is important because the permalink route matches all URLs including the /*slug-:id routes and would therefore prevent the redirect from being executed.

Finding the right homepage

The CMS object that is loaded when visiting the homepage path is determined by the choose_homepage callback. As a default, the object at the root path (/) is returned. To specify a different CMS object, use the following code:
Scrivito.configure do |config|
  config.choose_homepage do |env|
    Obj.root # Replace with code to set the homepage
  end
end

The scrivito_path helper automatically uses the homepage path if the CMS object passed to it is the current homepage.

If a single Scrivito application should serve multiple homepages, the full request data is available to decide which CMS object is the current homepage. This could be done based on the user stored in the session, the language set in their browser, the URL they are visiting, or any combination of these criteria. Let's take a look at how one could determine the current homepage based on the subdomain (e.g. “en.example.com” for English, and “fr.example.com” for French):

Scrivito.configure do |config|
  config.choose_homepage do |env|
    subdomain = ActionDispatch::Request.new(env).subdomain
    Homepage.where(:subdomain, :equals, subdomain).first
  end
end

The code assumes that there is a “Homepage” CMS object class, that it has an attribute named “subdomain,” and that proper subdomain names have been assigned to this attribute of the actual Homepage CMS objects. The query above then determines the Homepage to deliver from the value of this attribute.