Как ограничить форматы ресурсов в файле маршрутов Rails

При маршрутизации ресурсов в Rails дополнительный атрибут формата автоматически добавляется к сгенерированным маршрутам. Это значит, что данный ресурс можно запросить как XML, HTML и т.д. Какие форматы, которые фактически разрешены, обычно описываются в контроллере с помощью respond_to.

Но во многих случаях вы хотите только поддерживать HTML-код и чувствовать себя как накладные расходы, чтобы писать respond_to :html в каждом действии в каждом контроллере. Поэтому было бы здорово, если бы там был способ ограничить допустимые типы контента уже при построении маршрутов в файле route.rb, например.

map.resources :users, :formats => :html
map.resources :users, :formats => [:html, :xml]
map.resources :users, :formats => {:index => :html, :show => [:html, :xml]}

Есть ли способ достичь этого либо нативного, либо через плагин?

P.S. Обычный способ обойти это - просто игнорировать проблему и не использовать respond_to в действиях. Но это фактически не ограничивает допустимые типы контента. Вместо этого он просто ожидает, что шаблон существует в каталоге представлений для каждого возможного типа контента. Если по требованию не существует, система выдаст ошибку HTTP 500.

Ответы

Ответ 1

Вы должны обернуть эти маршруты в область видимости, если хотите ограничить их определенным форматом (например, html или json). К сожалению, ограничения в этом случае не работают должным образом.

Это пример такого блока...

scope :format => true, :constraints => { :format => 'json' } do
  get '/bar' => "bar#index_with_json"
end

Дополнительную информацию можно найти здесь: https://github.com/rails/rails/issues/5548

Этот ответ копируется из моего предыдущего ответа здесь.

Rails Routes - ограничение доступных форматов для ресурса

Ответ 2

Так как Rails использует эквивалент подстановочного знака для обработки форматов ".: format" его немного сложнее предотвратить на стороне маршрута.

Вместо этого это довольно простой способ поймать любые не HTML-запросы в переднем фильтре. Вот один из способов, которым это может выглядеть:

class ApplicationController < ActionController::Base
  before_filter :check_format

  private

    def check_format
      if request.format != Mime::HTML
        raise ActionController::RoutingError, "Format #{params[:format].inspect} not supported for #{request.path.inspect}"
      end
    end

end

ActionController:: RoutingErrors обрабатываются как 404 ошибок, которые разумны. Если у вас есть действие, которое должно поддерживать что-то другое, кроме HTML, просто используйте:

skip_before_filter :check_format, :only => ACTION_NAME

Ответ 3

Я считаю, что вы можете сделать что-то вроде этого:

respond_to do |format|
  format.html
  format.json { render :json => @things }
  format.any { render :text => "Invalid format", :status => 403 }
end

Если пользователь запрашивает html или json, он будет делать это как следует, но все остальное отобразит текст "Недопустимый формат".

Ответ 4

В любом случае вам не нужна ошибка HTTP 500? Как во второй строке вашего примера, если кто-то запросил JSON вместо HTML или XML, это не код ошибки, возвращающий соответствующий ответ?

Ответ 5

а не делать:

def some_action
  ...
  respond_to do |format|
    format.html
    format.json { whatever }
    format.any { whatever  }
  end
end

просто используйте:

def some_action
  ...
end

и Rails по умолчанию будет искать some_action.html.erb или любой другой формат. Если вы не определяете какие-либо представления, отличные от html, тогда все остальные форматы будут сбой при запросе.