Rails运行时的动态路由 [英] Dynamic routes on runtime in Rails
问题描述
我正在使用精炼厂开发一个站点。现在,对于在炼油厂后端中创建的一个特定页面,我想使用自己的控制器和视图。用户对该页面所做的全部工作就是设置菜单位置,标题,元信息等。该页面的URL必须与所有其他页面相同。
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
- 菜单2
- 特定页面
特定页面的网址类似于 locale / menu1 / menu2 /特定页面
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.
感谢您的帮助!
推荐答案
我需要自己在Rails 4应用程序(在下面的示例中称为 ComingSoon)中根据数据库模型构建路由。可以在后端进行编辑,并获得易于使用的名称,该名称存储在Page#name字段中,因此
关于我们
标题页通常变为about_us
名称,它导致http:// localhost:3000 / about_us
以下是我提出的技术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:在app / models / dynamic_router.rb中创建新模型
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
上面的关键是我将页面ID传递为其中一个参数,因此查找仍在Page#id字段上,即IMHO,比使用友好的插件或对模糊值进行查找要好得多。
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.
将以下行添加到config / routes.rb
Add the following line to your config/routes.rb
ComingSoon::Application.routes.draw do # ... DynamicRouter.load end
最后,当Page更新后,我们需要重新加载路由,因此在Page模型上添加一个after_safe回调:
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
我计划进一步完善此方法,以便仅在更改name属性时重新加载路由,并且也许只是编辑现有路由,而不是在性能证明是合理的情况下重新加载所有路由问题(目前还没有)。
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).
这篇关于Rails运行时的动态路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 菜单2