2010-11-08 10 views
7

I'm on Rails 2.3.5. En un controlador usuario típico crear una acciónError de cadena JSON no válido en Rails

class UsersController 
    def create 
    @user = User.new(params[:user]) 
    respond_to do |format] 
     if @user.save ... 
     else 
     format.json .... 
     end   
    end 
end 

Cuando un cliente pasa una cadena JSON inválida/malformada para la entrada, rieles tirar un error interno del servidor 500 diciendo "cadena JSON no válido". ¿Puedo capturar el error para poder dar un mensaje personalizado?

ACTUALIZADO Aquí está la pila según lo solicitado. Solo para que quede claro, sé que esta es una cadena JSON malformada, mi pregunta no es cómo reparar la cadena JSON sino cómo atrapar este error en particular para poder enviar un mensaje de error más significativo que HTTP 500 Internal Server Error . Gracias de antemano por su ayuda

Error occurred while parsing request parameters. 
Contents: 

user: {login: "John", email: "[email protected]", password: "111"}} 
/!\ FAILSAFE /!\ Mon Nov 08 02:01:04 -0800 2010 

    Status: 500 Internal Server Error 
    Invalid JSON string 
    c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/json/backends/yaml.rb:14:in `decode' 
    c:1:in `__send__' 
    c:1:in `decode' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:42:in `parse_formatted_parameters' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:11:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/session/cookie_store.rb:93:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/failsafe.rb:26:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `synchronize' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:114:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/reloader.rb:34:in `run' 
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:108:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/static.rb:31:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:46:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `each' 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `call' 
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/log_tailer.rb:17:in `call' 
    ... 
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/handler/mongrel.rb:34:in `run' 
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/commands/server.rb:111 
    c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require' 
    c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' 
    script/server:3 
re.rb:31:in `require' 
    script/server:3 
+0

¿Puedes poner una traza trasera completa, por favor? – shingara

Respuesta

6

He encontrado este complemento de rieles para que funcione en rieles 3.0.5: https://github.com/kares/request_exception_handler

Como Rob Cameron sugiere que cargue la aplicación de rieles y que levante parseError desde el código de la aplicación. No he probado su impacto en el rendimiento, pero parece funcionar bien.

+0

¡Este plugin funcionaba como un amuleto! – Myxtic

0

Buscando en /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/json/backends/yaml.rb (la verdad es un poco diferente versión), parece que se está levantando un ParseError. Suponiendo que el error se produce en "format.json", podría intentar algo así como

begin 
    format.json 
rescue ParseError => e 
    render :text => "Now there's some ugly JSON! (#{e.message})", :status => 500 
end 

Si eso no funciona, puede tratar de atraparlo antes usando la devolución de llamada rescue_from en su controlador.

class UsersController < ApplicationController 
... 
    rescue_from ParseError do |e| 
    render ... 
    end 
... 
end 
+0

Gracias por la sugerencia, lamentablemente el error no aparece en format.json. Creo que se ha planteado antes de que se llame a la acción user/create porque Rails necesita analizar la cadena JSON para obtener acceso a params. – Bob

+0

Ah, supongo que tiene sentido. En ese caso, intente rescue_from callback. He agregado un ejemplo arriba. – bioneuralnet

+1

Otra buena idea pero, por desgracia, no hay dados, el error se plantea antes de que llegue al controlador – Bob

0

Estoy corriendo con el mismo problema en este momento - Tengo una API que alguien podría pasar JSON válido para y quiero ser inteligentes acerca del error que regrese. Estoy ejecutando Rails 3.0.5. He seguido el error de ser arrojado a lib/active_support/json/backends/yaml.rb línea 17:

def decode(json) 
    if json.respond_to?(:read) 
    json = json.read 
    end 
    YAML.load(convert_json_to_yaml(json)) 
rescue ArgumentError 
    raise ParseError, "Invalid JSON string" 
end 

Así, json.read falla y lanza el error. Desafortunadamente, esto sucede mucho antes de que se invoca su controlador (es parte del análisis de parámetros de solicitud inicial donde Rails se une al Rack). Pensaría que para atrapar esto necesitarías agregar un pequeño parche para sobrescribir algunos de los lanzamientos de errores incorporados y en su lugar crear algo que puedas usar ... quizás podrías agregar un encabezado al objeto de solicitud que luego podrías detectar en tu controlador y lanzar tu propio error.

Lamentablemente, no creo que esto funcione para mí, ya que solo quiero anular el comportamiento al acceder a la API, no al resto del sitio. Aunque supongo que en el parche de mono, suponiendo que tengo acceso al objeto de solicitud, podría decirle que use mi nuevo comportamiento si la ruta solicitada coincide con una expresión regular como /\/api\//

+0

He resuelto este problema usando el middleware Rack. El middleware se inserta antes de ActionDispatch :: ParamsParser y detecta los errores emitidos por @ app.call.Dado que las acciones del controlador también son aplicaciones de rack en aplicaciones de rieles, puedo usar una acción de controlador para renderizar un bonito mensaje de error usando todas las plantillas de rieles. (Publicación para otras personas que llegan desde Google) https://gist.github.com/4709748 –

Cuestiones relacionadas