【问题标题】:Rails: Routing to a different controller based on request formatRails:根据请求格式路由到不同的控制器
【发布时间】:2012-12-06 23:01:21
【问题描述】:

我正在编写一个应用程序,我希望所有对 HTML 的请求都由同一个控制器操作处理。我还有一些其他特定于 JSON 的路由。这是我的路线的样子:

Blog::Application.routes.draw do
  constraints format: :json do
    resources :posts
  end

  match "(*path)" => "web#index"
end

问题在于constraints 被解释为“此路由仅适用于指定格式”,而不是“如果请求不是指定格式,则跳过此路由并尝试下一个路由。”

换句话说,在浏览器中导航到 /posts 会给我一个 406 Not Acceptable,因为 URL 被限制为 JSON 格式。相反,如果请求是针对 HTML 的,我希望它通过 web#index,如果请求是针对 JSON,则点击资源丰富的路由。如何实现?

(使用 Rails 3.2.9。)

【问题讨论】:

    标签: ruby-on-rails url-routing


    【解决方案1】:

    我已经考虑过了,并得出了一些结论。

    • 您可能不希望所有路由都返回单页应用程序 HTML,因为理想情况下您希望从某些路径返回 HTTP 404 状态代码。
    • 您的 HTTP 路由将不同于您的 JSON 路由
    • 您绝对应该将不同的格式路由到不同的控制器
    • 在 Rails 路由器中定义所有 HTML 路由可能会有好处,这样您就可以使用它来生成 javascript 路由器。至少有一颗宝石可以做到这一点
    • Rails 没有这个功能,而且这个 gem https://github.com/svenfuchs/routing-filter 看起来并不是一个合适的工具。这是我的尝试:Rails routing-filter route all html requests to one action
    • 必须在模块 Api 下为 JSON API 命名以避免路由冲突并不是一件坏事。
    • 不要在您的单页应用中包含对 Google 可见的内容,否则您将因重复内容而被禁止。

    我采取了一种稍微不同的方法,它并没有真正回答这个问题,但我认为它有几个优点:

    这是我的配置/routes.rb

    FooApp::Application.routes.draw do
    
      # Route all resources to your frontend controller. If you put this
      # in a namespace, it will expect to find another frontend controller
      # defined in that namespace, particularly useful if, for instance,
      # that namespace is called Admin and you want a separate single page
      # app for an admin interface. Also, you set a convention on the names
      # of your HTML controllers. Use Rails's action_missing method to
      # delegate all possible actions on your frontend controllers.
    
      def html_resources(name, options, &block)
        resources(name, options.merge(:controller => "frontend"), &block)
      end
    
      # JSON API
      namespace :api do
        resources :things, :except => [:edit, :new]
      end
    
      # HTML
      html_resources :things, :only => [:edit, :new, :index, :show] do
        get :other_action
      end
    end
    
    
    class FrontendController < ApplicationController
      def action_missing(*args, &block)
        render :index
      end
    end
    

    【讨论】:

      【解决方案2】:

      首先,我认为同一动作的不同控制器不是“Rails 方式”。 也许您可以使用中间件中的低级自定义请求处理程序来解决您的问题。

      【讨论】:

      • 不是真的......如果是单页应用程序,这可能正是您想要的。 Html 请求只是在客户端生成一个简单的布局。 Json 请求产生特定于路由的 json 输出。
      • 我听说 Google 的一些顶级 Rails 人员做过这种控制器分离,非常适合在单页应用程序中使用。拥有瘦控制器绝对是 Rails 方式,从 config/routes.rb 将多个 URL 路由到同一页面而不是在每个控制器方法中配置行为的干性和简单性也是如此。一般来说,为不同的关注点增加一个控制器比将每个控制器都耦合到该关注点要好。对不起,我会尽力想一个更好的答案。
      【解决方案3】:

      您可以在约束中使用格式,例如

      match '*path', constraints: { path: /foo.*/, format: 'html'}, to: 'home#index', via: [:get]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-26
        • 1970-01-01
        • 2020-01-03
        • 1970-01-01
        • 2011-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多