Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

root path for multiple controllers on rails routes

I have two resource controllers where I am using a slug to represent the ID. (friendly_id gem).

I am able to have the show path for one resource on the route but not for two at the same time. ie.

root :to => 'home#index'
match '/:id' => "properties#show"
match '/:id' => "contents#show"

Basically I want urls like,

# Content
domain.com/about-us
domain.com/terms
# Property
domain.com/unique-property-name
domain.com/another-unique-property-name

Whatever resource I put on top works. Is there a way to do this?

Thanks in advace if you can help.

like image 763
Lee Avatar asked Jan 17 '23 01:01

Lee


2 Answers

This is untested, but try utilizing a constraint on your route.

root :to => 'home#index'
match '/:id', :to => "properties#show",
              :constraints => lambda { |r| Property.find_by_id(r.params[:id]).present? }
match '/:id', :to => "contests#show",
              :constraints => lambda { |r| Contest.find_by_id(r.params[:id]).present? }

Alternatively, you can create a separate class that responds to matches? instead of defining a lambda proc. (I recommend placing these classes into separate files that will autoload within your Rails app.)

# app/constraints/property_constraint.rb
class PropertyConstraint
  def self.matches?(request)
    property = Property.find_by_id(request.params[:id])
    property.present?
  end
end

# app/constraints/contest_constraint.rb
class ContestConstraint
  def self.matches?(request)
    contest = Contest.find_by_id(request.params[:id])
    contest.present?
  end
end

# config/routes.rb
root :to => 'home#index'
match '/:id', :to => "properties#show", :constraints => PropertyConstraint
match '/:id', :to => "contests#show", :constraints => ContestConstraint

Unfortunately this results in an extra DB query (once in the routes, and once more in your controller). If anyone has a suggestion on minimizing this, please share. :)

like image 187
Matt Huggins Avatar answered Jan 30 '23 06:01

Matt Huggins


This Rails Engine does what you want:

Slug Engine at Github

Basically, the author's approach was to mount a Rails Engine inside his main app. This Engine incorporates both a controller for handling slugs that exist and a piece of middleware for filtering out and abstaining on slugs that don't exist.

He explains why he took this approach and other aborted solutions in a rather detailed and interesting blog post. This blog post and the slug engine source code should be enough detail for you to get your own code up and running, but that open-source engine seems to be exactly what you're looking for if you want a drop-in solution.

like image 38
ghoppe Avatar answered Jan 30 '23 06:01

ghoppe