1

我正在编写一个应用程序,我希望所有对 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。)

4

3 回答 3

2

我考虑过这个问题,得出了一些结论。

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

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

这是我的 config/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
于 2013-04-28T13:37:58.347 回答
0

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

于 2012-12-06T23:37:31.120 回答
0

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

match '*path', constraints: { path: /foo.*/, format: 'html'}, to: 'home#index', via: [:get]
于 2022-01-25T05:17:04.860 回答