我必须分开模型:嵌套的部分和文章,部分has_many文章。 两者都有路径属性,如aaa / bbb / ccc,例如:
movies # section
movies/popular # section
movies/popular/matrix # article
movies/popular/matrix-reloaded # article
...
movies/ratings # article
about # article
...
在我的路线中:
map.path '*path', :controller => 'path', :action => 'show'
如何创建像
这样的节目动作def show
if section = Section.find_by_path!(params[:path])
# run SectionsController, :show
elsif article = Article.find_by_path!(params[:path])
# run ArticlesController, :show
else
raise ActiveRecord::RecordNotFound.new(:)
end
end
答案 0 :(得分:1)
我不会实例化其他控制器,而是根据路径是否匹配某个部分或文章,从PathController的show动作中呈现不同的模板。即。
def show
if @section = Section.find_by_path!(params[:path])
render :template => 'section/show'
elsif @article = Article.find_by_path!(params[:path])
render :template => 'article/show'
else
# raise exception
end
end
原因在于,虽然您可以在另一个控制器中创建一个控制器的实例,但它不会按照您想要的方式工作。即第二个控制器无法访问你的参数,会话等,然后调用控制器将无法访问实例变量并在第二个控制器中进行渲染请求。
答案 1 :(得分:1)
您应该使用Rack中间件来拦截请求,然后为您正确的Rails应用程序重写URL。这样,您的路线文件仍然非常简单。
map.resources :section
map.resources :articles
在中间件中,您查找与路径关联的实体,并将URL重新映射到简单的内部URL,允许Rails路由分派到正确的控制器并正常调用过滤器链。
<强>更新强>
以下是使用Rails Metal组件和您提供的代码添加此类功能的简单演练。我建议您考虑简化路径段的查找方式,因为您使用当前代码复制了大量数据库工作。
$ script/generate metal path_rewriter
create app/metal
create app/metal/path_rewriter.rb
path_rewriter.rb
# Allow the metal piece to run in isolation
require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails)
class PathRewriter
def self.call(env)
path = env["PATH_INFO"]
new_path = path
if article = Article.find_by_path(path)
new_path = "/articles/#{article.id}"
elsif section = Section.find_by_path(path)
new_path = "/sections/#{section.id}"
end
env["REQUEST_PATH"] =
env["REQUEST_URI"] =
env["PATH_INFO"] = new_path
[404, {"Content-Type" => "text/html"}, [ ]]
end
end
有关使用Metal和Rack的简介,请查看Ryan Bates的Railscast episode on Metal和episode on Rack。