【问题标题】:Dynamic routes on runtime in RailsRails 运行时的动态路由
【发布时间】:2013-08-28 07:11:22
【问题描述】:

我正在使用炼油厂开发一个网站。现在对于在炼油厂后端创建的一个特定页面,我想使用我自己的控制器和视图。用户对该页面所能做的就是设置菜单位置、标题、元信息等。该页面的 URL 必须与所有其他页面看起来相同。

例如,菜单结构如下所示:

  • 菜单
  • 菜单1
    • 菜单2
      • 特定页面
  • 菜单

“特定页面”的 URL 看起来像“locale/menu1/menu2/特定页面”

该网站支持多种语言,因此我必须为所有语言创建这些路线。

目前我正在创建这样的路线:

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

有了这个,我得到了一条到上述每种语言的指定页面的路由。

但问题是,当用户更改页面名称或菜单中的位置时,必须重新生成路由,这并不经常这样做。

现在我的问题是,如何在运行时更动态地执行此操作?我读过一些关于约束的文章,但我不知道这是否是我需要的。

感谢您的帮助!

【问题讨论】:

  • 没有这样的默认路由 |获取“照片/:id”,到:“照片#show”|适合你吗?
  • 不,因为用户可以将照片转换成图片,那么路径必须是这样的:get 'pictures/:id', to: 'photos#show'
  • 如果你的控制器是相同的,你最好将路径的一部分转移到一个占位符并使用约束。可能是':name/:id', to: 'photos#show' 更好。
  • @Sano J:这个问题解决了吗?
  • @Michael Lang:当特定页面的菜单结构发生变化时,我会在运行时生成路由,这似乎不是一个很好但可行的解决方案

标签: ruby-on-rails ruby-on-rails-3 routes runtime refinerycms


【解决方案1】:

我需要自己在 Rails 4 应用程序(在下面的示例中称为“ComingSoon”)中弄清楚如何从数据库模型构建路由。我想要可以在后端编辑并提供用户友好的页面名称,存储在 Page#name 字段中。所以"About Us" 标题页通常会变成"about_us" 名称,从而导致"http://localhost:3000/about_us" 以下是我想出的技术:

在 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 字段上,即恕我直言,比使用友好插件或查找 slugerized 值要好得多。

将以下行添加到您的 config/routes.rb

ComingSoon::Application.routes.draw do

  # ...

  DynamicRouter.load
end

最后,当 Page 更新时,我们需要重新加载路由,所以在 Page 模型上添加一个 after_safe 回调:

class Page < ActiveRecord::Base
  after_save :reload_routes

  def reload_routes
    DynamicRouter.reload
  end
end

我计划进一步改进这一点,仅在更改名称属性时重新加载路由,并且可能只是编辑现有路由,而不是在性能被证明是一个问题时重新加载所有内容(目前不是)。

【讨论】:

  • 对于那些感兴趣的人,我在我的博客上发布了关于在运行时生成路由的更深入的内容:bit.ly/1c4Ppqc 欢迎在此处或博客文章本身发表评论!
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多