基于数据库的动态Rails路由

5
我正在使用Rails 2.3构建一个带有各种模块(博客、日历等)的CMS。每个模块都由不同的控制器处理,这很好地运作着。唯一的问题是根URL。根据用户选择的配置,此默认URL应显示不同的模块,即不同的控制器,但我确定正确控制器的唯一方法是通过检查数据库中要显示的“默认”模块。
目前,我正在使用特定的“root”控制器来检查数据库并重定向到正确的控制器。但是,我希望URL不被更改,这意味着我想从同一请求中调用正确的控制器。
我已经尝试使用Rails Metal获取此信息并手动调用所需的控制器,但我认为我可能正在重新发明轮子(识别请求路径以选择控制器,管理会话等)。
有什么想法吗?非常感谢!
2个回答

6
这个问题可以通过一些Rack中间件解决:
lib/root_rewriter.rb文件中的代码:
module DefV
  class RootRewriter
    def initialize(app)
      @app = app
    end

    def call(env)
      if env['REQUEST_URI'] == '/' # Root is requested!
        env['REQUEST_URI'] = Page.find_by_root(true).uri # for example /blog/
      end

      @app.call(env)
    end
  end
end

然后在您的config/environment.rb文件底部进行如下配置:

require 'root_rewriter'
ActionController::Dispatcher.middleware.insert_after ActiveRecord::QueryCache, DefV::RootRewriter

这个中间件将检查请求的页面(REQUEST_URI)是否为“/”,然后查找实际路径(实现取决于您;-))。您可以在某处缓存此信息(Cache.fetch('root_path') { Page.find... })。
检查REQUEST_URI存在一些问题,因为并非所有web服务器都能正确传递此参数。有关Rails中的整个实现细节,请参见http://api.rubyonrails.org/classes/ActionController/Request.html#M000720(点击“查看源代码”)。

是的,这个可以!这更或多或少是我之前一直尝试做的事情,但直到现在都没有成功。谢谢 Jan! - Nicolas Jacobeus

2
在Rails 3.2中,我想到的是以下内容(仍然是中间件):
class RootRewriter
  def initialize(app)
    @app = app
  end

  def call(env)
    if ['', '/'].include? env['PATH_INFO']
      default_thing = # Do your model lookup here to determine your default item
      env['PATH_INFO'] = # Assemble your new 'internal' path here (a string)
      # I found useful methods to be: ActiveModel::Naming.route_key() and to_param
    end

    @app.call(env)
  end
end

这告诉Rails,路径与请求的路径(根路径)不同,因此对link_to_unless_current等的引用仍然有效。

在初始化器中按照以下方式加载中间件:

MyApp::Application.config.middleware.use RootRewriter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接