Simon Somlai Simon Somlai - 2 months ago 10
Ruby Question

How To Remove Controller Names From Multiple Rails Routes?

I have two models in my app: articles and pages. I'd like the url to look like this;

www.mysite.com/this-is-the-title-of-the-article (articles#show)
www.mysite.com/about-me (pages#show)


A bit similar to regular wordpress routes, but with rails this seems like a big hassle. I've found a working solution, but it could probably be improved upon. Here's what I got;

Inside routes.rb;

resources :articles, :pages
# this redirects /:id requests to my StaticPagesController
match ':id' => 'static_pages#redirect', :via => [:get]
resources :articles, :only => [:show], :path => '', as: "articles_show"
resources :pages, :only => [:show], :path => '', as: "pages_show"


Inside StaticPagesController;

# Basically, it checks if there's a page or article with the given id and renders the corresponding show. Else it shows the 404
def redirect
@article = Article.where(slug_nl: params[:id]).first || Article.where(slug_en: params[:id]).first
@page = Page.where(slug: params[:id]).first
if !@page.nil?
@page = Page.friendly.find(params[:id])
render(:template => 'pages/show')
elsif !@article.nil?
@article = Article.friendly.find(params[:id])
@relatedarticles = Article.where(category: @article.category).uniq.limit(6).where.not(id: @article)
render(:template => 'articles/show')
else
render(:template => 'common/404', :status => 404)
end
end


Note: I've swapped out the id for articles and pages with the title attribute (using the friendly_id gem). The articles are also in two languages (therefore I check for both slugs)

Any idea's? I've already tried some of these;



But they didn't quite did the trick so far. Thanks :) ♥

Answer

I improved the solution, but it still doesn't feel 100% rails-y. But, here's what I did to get;

  • /page-title (pages#show)
  • en/this-is-the-article (articles#show, en locale)
  • nl/dit-is-de-titel (articles#show, nl locale)

Note: I've swapped out the id for articles and pages with the title attribute (using the friendly_id gem). The articles are also in two languages (therefore I check for both slugs)

Routing.rb (modified from blog.arkency.com/2014/01/short-urls-for-every-route-in-your-rails-app

 resources :users, :projects, :testimonials, :articles, :pages
  class ArticleUrlConstrainer
    def matches?(request)
      id = request.path.gsub("/", "")[2..-1]
      @article = Article.where(slug_nl: id).first || Article.where(slug_en: id).first
      if I18n.locale == :en
        @article = Article.find_by(slug_en: id) || Article.find_by(slug_nl: id)
      else
        @article = Article.find_by(slug_nl: id) || Article.find_by(slug_en: id)
      end
    end
  end

  constraints(ArticleUrlConstrainer.new) do
    match '/:id', :via => [:get], to: "articles#show"
  end

  class PageUrlConstrainer
    def matches?(request)
      id = request.path.gsub("/", "")[2..-1]
      @page = Page.friendly.find(id)
    end
  end

  constraints(PageUrlConstrainer.new) do
    match '/:id', :via => [:get], to: "pages#show"
  end

  resources :articles, :only => [:show], :path => '', as: "articles_show"
  resources :pages, :only => [:show], :path => '', as: "pages_show"

Final