restful rails generate before and ruby-on-rails ruby actioncontroller

ruby-on-rails - generate - resources as rails



¿Rails viene con una excepción "no autorizada"? (2)

Estoy escribiendo una aplicación que utiliza objetos antiguos de Ruby (PORO) para abstraer la lógica de autorización de los controladores.

Actualmente, tengo una clase de excepción personalizada llamada NotAuthorized que rescue_from a nivel de controlador, pero tenía curiosidad por saber: ¿Rails 4 ya viene con una excepción para indicar que una acción no fue autorizada? ¿Estoy reinventando la rueda implementando esta excepción?

Aclaración : la raise AuthorizationException no ocurre en ningún lugar dentro de un controlador, sino dentro de un PORO completamente desacoplado fuera del controlador. El objeto no tiene conocimiento de HTTP, rutas o controladores.


Rails no parece asignar una excepción a :unauthorized .

Las asignaciones predeterminadas se definen en activerecord/lib/active_record/railtie.rb :

config.action_dispatch.rescue_responses.merge!( ''ActiveRecord::RecordNotFound'' => :not_found, ''ActiveRecord::StaleObjectError'' => :conflict, ''ActiveRecord::RecordInvalid'' => :unprocessable_entity, ''ActiveRecord::RecordNotSaved'' => :unprocessable_entity )

y actionpack/lib/action_dispatch/middleware/exception_wrapper.rb :

@@rescue_responses.merge!( ''ActionController::RoutingError'' => :not_found, ''AbstractController::ActionNotFound'' => :not_found, ''ActionController::MethodNotAllowed'' => :method_not_allowed, ''ActionController::UnknownHttpMethod'' => :method_not_allowed, ''ActionController::NotImplemented'' => :not_implemented, ''ActionController::UnknownFormat'' => :not_acceptable, ''ActionController::InvalidAuthenticityToken'' => :unprocessable_entity, ''ActionDispatch::ParamsParser::ParseError'' => :bad_request, ''ActionController::BadRequest'' => :bad_request, ''ActionController::ParameterMissing'' => :bad_request )

Puede agregar una excepción personalizada desde la configuración de su aplicación (o un Railtie personalizado):

Your::Application.configure do config.action_dispatch.rescue_responses.merge!( ''AuthorizationException'' => :unauthorized ) # ... end

O simplemente use rescue_from .


Supongo que la razón por la que Rails no introdujo esta excepción es porque la Autorización y la Autenticación no es el comportamiento nativo de Rails (sin considerar el basicauth, por supuesto).

Por lo general, estas son responsabilidades de otras bibliotecas Diseñadas para NotAuthenticated; Pundit , CanCanCan, Rollify para NotAuthorized) En realidad diría que puede ser malo extender ActionController con excepciones personalizadas como ActionController::NotAuthorized (porque como dije, no es su responsabilidad)

Entonces, la forma en que generalmente resolví este problema es que introduje excepciones personalizadas en ApplicationController

class ApplicationController < ActionController::Base NotAuthorized = Class.new(StandardError) # ...or if you really want it to be ActionController # NotAuthorized = Class.new(ActionController::RoutingError) rescue_from ActiveRecord::RecordNotFound do |exception| render_error_page(status: 404, text: ''Not found'') end rescue_from ApplicationController::NotAuthorized do |exception| render_error_page(status: 403, text: ''Forbidden'') end private def render_error_page(status:, text:, template: ''errors/routing'') respond_to do |format| format.json { render json: {errors: [message: "#{status} #{text}"]}, status: status } format.html { render template: template, status: status, layout: false } format.any { head status } end end end

Por eso en mis controladores puedo hacer

class MyStuff < ApplicationController def index if current_user.admin? # .... else raise ApplicationController::NotAuthorized end end end

Esto define claramente que la capa en la que espera que se levante y se capture esta excepción es su capa de aplicación, no la biblioteca de terceros.

La cosa es que las bibliotecas pueden cambiar (y sí, esto también significa que Rails también) definir una excepción en una clase de biblioteca de terceros y rescatarla en la capa de su aplicación es realmente peligroso, ya que el significado de la clase de excepción frena su rescue_from

Puede leer muchos artículos en los que la gente está Waring sobre Rails raise - rescue_from es el goto moderno (ahora considerando el anti-patrón entre algunos expertos) y en cierta medida es cierto, pero solo si está rescatando excepciones que no tiene. Control total apagado !!

Eso significa excepciones de terceros (incluidos Devise y Rails hasta cierto punto). Si define las clases de excepciones en su aplicación, no está retransmitiendo en la tercera parte lib => tiene control total => puede rescue_from sin que esto sea un antipatrón.