3

I would like to do just a little bit of extra logic in rotues.rb, that probably doesn't belong there, but it seems to make the most sense to me.

I have two conflicting routes. To be primitive:

match '/videos/:browseby' => 'videos#browse', :as => "browse_by"

Where :browseby is looking for a string, such as "Tags", to browse videos by tags.

However, (and most probably saw this coming) I also have my basic show resource (again in primitive form):

match '/videos/:id' => 'videos#show', :as => "video"

Where :id is looking for the integer for the video ID.

Is there a way to add a small bit of logic such as...

match '/videos/:id' => 'videos#show', :as => "video", :format(:id) => :integer

(Which is my hypothetical rails syntax, to help show what I'm looking for.)

I know I can munch this in the Controller level, but it makes more sense to me to handle it at the route level.

Kyle Macey
  • 8,074
  • 2
  • 38
  • 78

1 Answers1

5

You could try using :constraints and a regex:

match '/videos/:id' => 'videos#show', :as => "video", :constraints => { :id => /\d/ }
match '/videos/:browseby' => 'videos#browse', :as => "browse_by"

You'll also want to make sure the looser :browseby version comes after the :id version. Note that regex constraints are implicitly anchored at the beginning so that would work as long as your :browseby values didn't start with a number.

If you have tags that do start with numbers then you could use an object for the constraint and then you could include anchors in your regex:

class VideoIdsOnly
    def matches?(request)
        request.path =~ %r{\A/videos/\d+\z}
    end
end

match '/videos/:id' => 'video#show', :as => "video", :constraints => VideoIdsOnly.new
match '/videos/:browseby' => 'videos#browse', :as => "browse_by"
mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • @Kyle: Thanks, been there done that and my mother taught me to share. I had to do some guesswork with the `VideoIdsOnly` version as that stuff isn't exactly well documented. – mu is too short Jan 18 '12 at 02:01
  • It seems like that sort of method, however, and its implementation could really bring a whole new level of dynamic routes... – Kyle Macey Jan 18 '12 at 02:03
  • I think routing could be vastly improved if you could say things like "`:id` should be an integer greater than zero and you should be able to turn into an `X` instance using `X.find` and `X.can_access(current_user)` should be true and then `params[:id]` would be that `X` instance. I built something like that in a different language, wiped out a huge class of bugs in one shot. Maybe I'll get time to do it for Rails one of these days. – mu is too short Jan 18 '12 at 02:07
  • Well, the :browseby isn't pretty in and of itself, either. It has to be Uber validated because it directly takes URL argument into an eval statement. So I use controller logic to compare the entry against an array of valid possibilities. (technically the input is not a model, but a tagging from acts_as_taggable_on, killing nested resource routing) – Kyle Macey Jan 18 '12 at 02:13
  • The `:constraints` class approach might work for that one or just white list it in the controller. – mu is too short Jan 18 '12 at 02:23