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.