Dynamic routes on runtime in Rails

喜夏-厌秋 提交于 2019-12-24 12:51:24

问题


I'm developing a site using refinery. Now for one specific page that is created in the back-end of refinery, i want to use my own controller and views. All the User can do with this page is to set the menu-position, title, meta-info etc. The URL for this page has to look the same as all the other pages.

So for example, the menu structure looks like:

  • menux
  • menu1
    • menu2
      • specific page
  • menux

And the URL for "specific page" looks like "locale/menu1/menu2/specific page"

The site is available in multiple languages, so i have to create these routes for all languages.

Currently i'm creating the routes like this:

specific_page_id = 1
Refinery::I18n.frontend_locales.each do |lang|
  slugs = []
  page = Refinery::Page.find_by_path_or_id(nil, specific_page_id)
  # get slug for page in current language
  slugs << page.translations.select { |p|  p.locale == lang  }.first.slug

  # get all slugs from parrent pages
  while !page.parent_id.blank?
    page = Refinery::Page.find_by_path_or_id(nil, page.parent_id)
    slugs << page.translations.select { |p|  p.locale == lang  }.first.slug
  end

  match "/:locale/#{slugs.reverse.join("/")}"  => "controller#action", :via => :get, :constraints => { :locale => /#{lang}/ }
end

With this, i'm getting a route to the specified page in every language like described above.

But the problem is, when the user changes the name of the page or the position in the menu, the routes have to be generated again, which isn't done too often.

Now my question is, how can i do this more dynamically on run-time? I've read a bit about constraints but i don't know if this is what i need.

Thanks for your help!


回答1:


I needed to figure out building routes off a database model myself in a Rails 4 application (which is called "ComingSoon" in the examples below. I wanted pages that could be edited on the back-end and given a user-friendly name, which is stored in the Page#name field. So "About Us" titled page typically becomes "about_us" name, which leads to "http://localhost:3000/about_us" The following is the technique I came up with:

Create a new model in app/models/dynamic_router.rb

class DynamicRouter
  def self.load
    ComingSoon::Application.routes.draw do
      Page.all.each do |pg|
        get "/#{pg.name}", :to => "pages#show", defaults: { id: pg.id }, as: "pages_#{pg.name}"
      end
    end
  end

  def self.reload
    ComingSoon::Application.routes_reloader.reload!
  end
end

The key above is that I pass the page's id as one of the parameters, so look up is still on the Page#id field, which is, IMHO, a lot better than using the friendly plugin or lookups on slugerized values.

Add the following line to your config/routes.rb

ComingSoon::Application.routes.draw do

  # ...

  DynamicRouter.load
end

Finally, when the Page is updated, we need to reload the routes, so add an after_safe callback on the Page model:

class Page < ActiveRecord::Base
  after_save :reload_routes

  def reload_routes
    DynamicRouter.reload
  end
end

I plan to refine this further to only reload routes if the name attribute is changed and perhaps simply edit the existing route rather than reloading everything if performance proves to be an issue (which at the moment, its not).



来源:https://stackoverflow.com/questions/18481458/dynamic-routes-on-runtime-in-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!