代码之家  ›  专栏  ›  技术社区  ›  tig Charlie Martin

开关轨控制器

  •  0
  • tig Charlie Martin  · 技术社区  · 15 年前

    我必须分开模型:嵌套的部分和文章,部分有很多文章。 两者都具有类似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
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   Duncan Beevers    15 年前

    您应该使用机架中间件拦截请求,然后为您的正确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
    

    要了解如何使用金属和机架,请查看Ryan Bates的Railscast。 episode on Metal episode on Rack .

        2
  •  1
  •   mikej heading_to_tahiti    15 年前

    与实例化其他控制器不同,我只呈现一个不同于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
    

    原因是,虽然您可以在另一个控制器中创建一个控制器的实例,但它不会按您希望的方式工作。也就是说,第二个控制器将无法访问您的参数、会话等,然后调用控制器将无法访问实例变量和呈现在第二个控制器中发出的请求。