2013-04-04 2 views
7

Я ищу для отображения сообщения об ошибке в представлении jbuilder. Например, один маршрут я мог бы может быть:Rails правильный способ отображения ошибки с jbuilder

/foos/:id/bars

Если :id представленного пользователем не существует или является недействительным, я хотел бы быть в состоянии отобразить сообщение об ошибке, соответственно, в моем index.json.builder файле ,

Использование Rails, что является лучшим способом сделать это? Контроллер может иметь что-то такое, как:

def index 
    @bar = Bar.where(:foo_id => params[:id]) 
end 

В этом случае, может быть params[:id]nil, или что объект не может существовать. Я не уверен, что самое лучшее, что можно сделать здесь, это обработать его в контроллере и явно визуализировать error.json.builder или обработать его в самом представлении index.json.builder. Каков правильный способ сделать это, и если он находится в index.json.builder, есть params[:id], доступный для проверки там? Я знаю, что вижу, @bar.nil?, но не уверен в обратном?

ответ

4

Я бы оказать index.json.builder или просто встроенный JSON с :error => 'not found' И не забудьте установить соответствующий статус HTTP: :status => 404

Так результат может выглядеть следующим образом:

render :json => { :error => 'not found' }, :status => 422 if @bar.nil? 
4

I думаю, что вы имели в виду шоу, поскольку индекс действительно для списков/коллекций. И вы должны получить .first о том, где, иначе у вас просто есть отношение, не так ли? Затем используйте .first!, чтобы поднять ошибку, поскольку промежуточное ПО Rails Rack в Rails 4 public_exceptions будет обрабатываться в основном способом, например.

def show 
    # need to do to_s on params value if affected by security issue CVE-2013-1854 
    @bar = Bar.where(:foo_id => params[:id].to_s).first! 
end 

Вы также можете использовать @bar = Bar.find(params[:id]), но устарела и будет удалена в Rails 4.1, после чего вы должны добавить к вашему gem 'activerecord-deprecated_finders' Gemfile использовать.

Для индекса, вы, вероятно, хотите @bars = Bar.all. Если по какой-то причине вы хотите отфильтровать и не хотите использовать область видимости и т. Д., Тогда вы можете использовать @bars = Bar.where(...).to_a или аналогичный.

Rails 4: Основная Обработка исключений в стеллаже Автоматической

Пока запрос пинает ошибку, Rails 4 должно быть в состоянии вернуть часть сообщения об ошибке для любого поддерживаемого формата where to_(format) может быть вызван хэш (например, json, xml и т. д.).

Чтобы узнать, почему, взгляните на стойку Rails public_exceptions промежуточное ПО.

Если это html, он попытается прочитать в связанном файле из общего каталога в Rails для кода состояния (например, 500.html для ошибки сервера/HTTP 500).

Если это какой-то другой формат, он попытается сделать to_(the format) на хеш: { :status => status, :error => exception.message }.Чтобы увидеть, как это будет работать, перейти на рельсы консоль:

$ rails c 
... 
1.9.3p392 :001 > {status: 500, error: "herro shraggy!"}.to_xml 
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <status type=\"integer\">500</status>\n <error>herro shraggy!</error>\n</hash>\n" 
1.9.3p392 :002 > {status: 500, error: "herro shraggy!"}.to_json 
=> "{\"status\":500,\"error\":\"herro shraggy!\"}" 

В промежуточном слое, вы увидите X-Cascade заголовок в коде и в различных местах, связанных с Rails' обработки исключений в стойке. Per this answer, заголовок X-Cascade установлен в pass, чтобы сообщить Rack, чтобы попробовать другие маршруты, чтобы найти ресурс.

Rails 3.2.x: может обрабатывать исключения в стойку

В Rails 3.2.x, что код, чтобы сделать to_(format) для тела ответа и т.д. не в public_exceptions.rb. Он обрабатывает только html-формат.

Возможно, вы можете попробовать заменить старое промежуточное ПО на более новую версию с помощью патча.

Если вы хотите, чтобы Rack обрабатывал вашу ошибку более конкретным образом без патча, см. № 3 в сообщении Жозе Валима «My five favorite “hidden” features in Rails 3.2».

В этом и another answer также упоминает, вы можете использовать config.exceptions_app = self.routes. Затем с помощью маршрутов, которые указывают на пользовательский контроллер, вы можете обрабатывать ошибки с любого контроллера, как и любые другие запросы. Обратите внимание на бит около config.consider_all_requests_local = false в вашем config/environments/development.rb.

Вам не нужно использовать маршруты для использования exceptions_app. Хотя это может быть немного пугающим, это просто proc/lambda, который принимает хэш и возвращает массив, формат которого равен: [http_status_code_number, {headers hash...}, ['the response body']]. Например, вы должны быть в состоянии сделать это в Rails 3.2.x конфигурации, чтобы сделать его обрабатывать ошибки, как Rails 4.0 (это последняя public_exceptions промежуточного слоя разрушилась):

config.exceptions_app = lambda do |env| 
    exception = env["action_dispatch.exception"] 
    status = env["PATH_INFO"][1..-1] 
    request = ActionDispatch::Request.new(env) 
    content_type = request.formats.first 
    body = { :status => status, :error => exception.message } 
    format = content_type && "to_#{content_type.to_sym}" 
    if format && body.respond_to?(format) 
    formatted_body = body.public_send(format) 
    [status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", 
      'Content-Length' => body.bytesize.to_s}, [formatted_body]] 
    else 
    found = false 
    path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale 
    path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path)) 

    if found || File.exist?(path) 
     [status, {'Content-Type' => "text/html; charset=#{ActionDispatch::Response.default_charset}", 
       'Content-Length' => body.bytesize.to_s}, [File.read(path)]] 
    else 
     [404, { "X-Cascade" => "pass" }, []] 
    end 
    end 
end 

Примечание: Для любой проблемы с этой обработкой , отказоустойчивая реализация находится в ActionDispatch::ShowExceptionshere.

Rails 3 и 4: Обработка некоторых исключений в Rails Controller

Если вы не хотите иметь рендеринг ошибки в самом контроллере, вы можете сделать:

def show 
    respond_with @bar = Bar.where(:foo_id => params[:id].to_s).first! 
rescue ActiveRecord::RecordNotFound => e 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Но вам не нужно для повышения ошибок. Вы также можете сделать:

def show 
    @bar = Bar.where(:foo_id => params[:id].to_s).first 
    if @bar 
    respond_with @bar 
    else 
    respond_to do |format| 
     format.json => { :error => "Couldn't find Bar with id=#{params[:id]}" }, :status => 404 
    end 
    end 
end 

Вы также можете использовать rescue_from, например, в контроллере, или ApplicationController и т.д .:

rescue_from ActiveRecord::RecordNotFound, with: :not_found 

def not_found(exception) 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

или:

rescue_from ActiveRecord::RecordNotFound do |exception| 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Хотя некоторые наиболее часто встречающиеся ошибки могут быть обработаны в контроллере, если вы ошибка, связанная с отсутствующими маршрутами и т.д. отформатирована в формате JSON и т. д., их необходимо обрабатывать в промежуточном ПО Rack.