Исключение для неправильного формата в rails

#ruby-on-rails #exception

#ruby-on-rails #исключение

Вопрос:

Я пытаюсь проверить, является ли формат, отправляемый через URL-адрес запроса, json или нет?

итак, в link_to я отправил формат следующим образом

 <%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url, format: 'xml'} %>
  

В соответствующем контроллере я перехватываю параметр и вызываю исключение следующим образом

        format_request = params[:format]
        if format_request != "json"
         raise DRI::Exceptions::NotImplemented   
        end
  

но исключение не отображается, вместо этого сервер просто столкнулся с внутренней ошибкой, но если я изменил параметр внутри контроллера, тогда отобразится исключение, поэтому, если URL-адрес такой

<%= link_to «Embed», {:controller=>’api/oembed’,:action => ‘show’,:url => catalog_url, формат: ‘json’} %>

        format_request = "xml"
        if format_request != "json"
         raise DRI::Exceptions::NotImplemented   
        end
  

почему исключение 501 не срабатывает, если я отправляю формат как xml в URL? Я делаю это с целью тестирования, чтобы в случае, если кто-то отправит запрос с неправильным форматом, отображалось ожидание 501

Комментарии:

1. Используйте request.format вместо params[:format], который присутствует только в том случае, если вы явно передаете этот параметр. Это также экземпляр запроса строки, поэтому вы можете сделать request.format.xml ? Что намного более рубиново, чем сравнение со строкой — и используйте, если вместо != .

2. Но вы действительно изобретаете колесо здесь, чтобы. Rails имеет MimeResponds, который уже реализует эту функциональность.

3. Я попробовал, но все то же самое, он не отображает исключение: (

4. поскольку у вас на самом деле нет воспроизводимого примера, я понятия не имею, что именно вы испортили. Я могу просто указать на очевидное, например, не изобретать велосипед. api.rubyonrails.org/classes/ActionController/MimeResponds.html и используйте rescue_from, если вы хотите обработать исключение.

5. Да. Если вы используете MimeResponds, это вызовет ошибку, если контроллер не обрабатывает формат запроса. Таким образом, изобретая велосипед.

Ответ №1:

Используйте ActionController::MimeResponds вместо того, чтобы плохо изобретать колесо:

 # or whatever your base controller class is
class ApplicationController < ActionController::API
  # MimeResponds is not included in ActionController::API
  include ActionController::MimeResponds
  # Defining this in your parent class avoids repeating the same error handling code 
  rescue_from ActionController::UnknownFormat do
    raise DRI::Exceptions::NotImplemented # do you really need to add another layer of complexity?
  end
end

module Api
  class OembedController < ApplicationController
    def oembed
      respond_to :json
    end
  end
end
  

Если вы не используете respond_to Rails, неявно предполагается, что контроллер отвечает на все форматы ответов. Но если вы явно перечислите форматы, на которые вы отвечаете, с помощью списка символов (или более распространенного блочного синтаксиса), Rails вызовет ActionController::UnknownFormat , если формат запроса отсутствует в списке. Вы можете сохранить исключения, с rescue_from помощью которых вы можете использовать наследование вместо того, чтобы повторяться с той же обработкой ошибок.

Ответ №2:

Как упоминает @max, отправка format: 'xml' не требуется, поскольку Rails уже знает формат запроса.

 <%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url } %>
  

В контроллере:

 def oembed
  respond_to do |format|
    format.json { # do the thing you want }
    format.any(:xml, :html) { # render your DRI::Exceptions::NotImplemented }
  end
end
  

Или, если вы хотите больше контроля, вы можете перейти к пользовательскому действию:

 def oembed
  respond_to do |format|
    format.json { # do the thing you want }
    format.any(:xml, :html) { render not_implemented }
  end
end

def not_implemented
  # just suggestions here
  flash[:notice] = 'No support for non-JSON requests at this time'
  redirect_to return_path
  # or if you really want to throw an error
  raise DRI::Exceptions::NotImplemented
end
  

Если вы действительно хотите изобрести колесо (это ваше колесо, изобретайте, если хотите):

Я бы переименовал format во что-то другое, оно, вероятно, зарезервировано и может вызвать у вас проблемы

 <%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url, custom_format: 'xml'} %>
  

Затем в вашем контроллере вам необходимо явно разрешить этот параметр:

 def oembed
  raise DRI::Exceptions::NotImplemented unless format_params[:custom_format] == 'json'
end

private

def format_params
  params.permit(:custom_format)
end
  

Комментарии:

1. Вы на правильном пути, но лучшим решением здесь действительно является не отвечать на типы, которые вы не поддерживаете, и перехватывать ActionController::UnknownFormat исключение, поскольку оно является СУХИМ и будет досрочно прекращено, что предотвратит выполнение действия контроллера. Также да — format параметр зарезервирован — для указания формата запроса. Он имеет приоритет над заголовками запроса.

2. Я согласен с вами, @max, я бы просто сказал, что ваше решение на несколько уровней глубже (и правильнее), но может показаться слишком глубоким для OP, для меня это почти так, и у меня за плечами 5 лет Ruby.

3.Глубокий конец? Этот материал описан в руководствах и является довольно фундаментальным знанием rails. guides.rubyonrails.org/action_controller_overview.html#rescue guides.rubyonrails.org /…

4. Глубокий конец в смысле «MVC» -уровень против унаследованный уровень (Application, ApplicationRecord, ApplicationController)