3

For several projects I need something to simplify my routes to remove the controller name for one of the most important routes. In this case editions, so instead of

domain.com/editions/london/venues/the-venue

We use ->

domain.com/london/venues/the-venue

I've been using this formula for my routing:

  # MUST BE LAST
  resources :editions, path: '' do
    get 'set_session', on: :member
    resources :events
    resources :quiz_masters
    resources :venues
  end

And it works fine, but I feel there's something unpleasant about it. I'm wondering if there's a better alternative, one which also has constraints, so I don't have to worry about sticking it always at the bottom of my routes.

I'm also not sure path: '' is a good way to do it? Even though it works.

ere
  • 1,739
  • 3
  • 19
  • 41
  • eg I could constrain it somehow with `:constraints => proc { |req| Edition.all.map(&:slug).include?(req.params[:edition_id]) }` ? – ere Jul 02 '14 at 07:58
  • This is something we've been wresting with too - the best solution we have is what you've put in your question, if you have a single instance of wanting to use no resource definition in your routes itself – Richard Peck Jul 02 '14 at 08:32
  • Yeah, it just feels a little like a hack. On the one hand I don't like opening all the routes up with path: "" on the other I don't like the idea of putting a constraint in my routes that has to touch the DB! DIRTY! – ere Jul 02 '14 at 08:50
  • Writing answer for you. Won't help you much, but will explain some things – Richard Peck Jul 02 '14 at 08:52

3 Answers3

3

Routes

In case you're lapse on answers, I'll detail how we do this, which is to say we do exactly the same as you have explained in your question:

#config/routes.rb
... @bottom
resources :events, path: "" do
   resources :venues
   # ...
end

This only works for single resources (you can't have more than one path: '') as it will conflict if you have multiple references. As you mentioned, this should go at the bottom of your routes (even below root). We use this setup currently


App-Wide Slugs

Something you may benefit from is to create some way to handle app-wide slugs

We've not done this, but could theoretically be handled by using some sort of middleware / simple model with polymorphic association to determine where to route the request.

For example, as per the referenced question, you may be able to have a model as follows:

#app/models/slug.rb
Class Slug < ActiveRecord::Base
   belongs_to :sluggable, polymorphic: true
end

#slugs table
id | sluggable_id | sluggable_type | created_at | updated_at

Then you could handle the slugs of your models like this:

#app/models/concerns/slugged.rb
Class Slugged
    extend ActiveSupport::Concern

    included do
       has_one :slug, as: :sluggable
       before_save :build_slug
    end
end

This should allow you to then pick up the slugs in some slug middleware, and route to the correct controller. A "hack" maybe, but it's the most extensive & modular way

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
3

Using your example, you probably should constrain it. Either using the Edition.all.map(&:slug) array you included or cache it in some way depending on how big the list is. This way it will be limited and wouldn't necessarily need to be at the bottom of the routes file.

resources :editions, path: '', :constraints => proc { |req| ['london', 'other_cities'].include?(req.params[:edition_id]) } do
  get 'set_session', on: :member
  resources :events
  resources :quiz_masters
  resources :venues
end
0

It seems to me that the awkwardness comes from the need and the linear nature of routes and URLs, not from your solution. Something about that code (same as Rich's) feels a bit unpleasant, as you say, and perhaps "not the Rails way"; but Rails is meant to be bent when necessary, and I can't think of a more effective way to accomplish what you're doing.

If the first term in the route is a slug ("/london/"), the route must be defined last. I can't imagine any way around that, and don't think you should lose any sleep or peace of mind looking for an alternative.

Any interesting app will push the limits of the framework it's written in, and that means there will always be some awkward bits of code.

Topher Hunt
  • 4,404
  • 2
  • 27
  • 51