rails gema función example español ejemplos cuál ruby-on-rails devise ruby-on-rails-4

ruby on rails - gema - ActionController:: InvalidAuthenticityToken en RegistrationsController#create



devise rails español (6)

Debes poner protect_from_forgery justo antes de la acción para autenticar al usuario. Esta es la solución correcta

class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :authenticate_user! end

Hola, estoy usando Devise para mi autenticación de usuario. De repente mi nuevo registro de usuario no funcionaba.

esto fue un error que estoy recibiendo.

ActionController::InvalidAuthenticityToken Rails.root: /home/example/app Application Trace | Framework Trace | Full Trace Request Parameters: {"utf8"=>"✓", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "x"=>"0", "y"=>"0"}

este es mi controlador de registros

class RegistrationsController < Devise::RegistrationsController prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ] prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy] before_filter :configure_permitted_parameters prepend_view_path ''app/views/devise'' # GET /resource/sign_up def new build_resource({}) respond_with self.resource end # POST /resource def create build_resource(sign_up_params) if resource.save if resource.active_for_authentication? set_flash_message :notice, :signed_up if is_navigational_format? sign_up(resource_name, resource) respond_with resource, :location => after_sign_up_path_for(resource) else set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? expire_session_data_after_sign_in! respond_with resource, :location => after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource respond_to do |format| format.json { render :json => resource.errors, :status => :unprocessable_entity } format.html { respond_with resource } end end end # GET /resource/edit def edit render :edit end # PUT /resource # We need to use a copy of the resource because we don''t want to change # the current user in place. def update self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key) prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email) if update_resource(resource, account_update_params) if is_navigational_format? flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ? :update_needs_confirmation : :updated set_flash_message :notice, flash_key end sign_in resource_name, resource, :bypass => true respond_with resource, :location => after_update_path_for(resource) else clean_up_passwords resource respond_with resource end end # DELETE /resource def destroy resource.destroy Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name) set_flash_message :notice, :destroyed if is_navigational_format? respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) } end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. def cancel expire_session_data_after_sign_in! redirect_to new_registration_path(resource_name) end protected # Custom Fields def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_up) do |u| u.permit(:first_name, :last_name, :email, :password, :password_confirmation) end end def update_needs_confirmation?(resource, previous) resource.respond_to?(:pending_reconfirmation?) && resource.pending_reconfirmation? && previous != resource.unconfirmed_email end # By default we want to require a password checks on update. # You can overwrite this method in your own RegistrationsController. def update_resource(resource, params) resource.update_with_password(params) end # Build a devise resource passing in the session. Useful to move # temporary session data to the newly created user. def build_resource(hash=nil) self.resource = resource_class.new_with_session(hash || {}, session) end # Signs in a user on sign up. You can overwrite this method in your own # RegistrationsController. def sign_up(resource_name, resource) sign_in(resource_name, resource) end # The path used after sign up. You need to overwrite this method # in your own RegistrationsController. def after_sign_up_path_for(resource) after_sign_in_path_for(resource) end # The path used after sign up for inactive accounts. You need to overwrite # this method in your own RegistrationsController. def after_inactive_sign_up_path_for(resource) respond_to?(:root_path) ? root_path : "/" end # The default url to be used after updating a resource. You need to overwrite # this method in your own RegistrationsController. def after_update_path_for(resource) signed_in_root_path(resource) end # Authenticates the current scope and gets the current resource from the session. def authenticate_scope! send(:"authenticate_#{resource_name}!", :force => true) self.resource = send(:"current_#{resource_name}") end def sign_up_params devise_parameter_sanitizer.sanitize(:sign_up) end def account_update_params devise_parameter_sanitizer.sanitize(:account_update) end end

y este es mi controlador de sesiones

class SessionsController < DeviseController prepend_before_filter :require_no_authentication, :only => [ :new, :create ] prepend_before_filter :allow_params_authentication!, :only => :create prepend_before_filter { request.env["devise.skip_timeout"] = true } prepend_view_path ''app/views/devise'' # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) respond_with(resource, serialize_options(resource)) end # POST /resource/sign_in def create self.resource = warden.authenticate!(auth_options) set_flash_message(:notice, :signed_in) if is_navigational_format? sign_in(resource_name, resource) respond_to do |format| format.json { render :json => {}, :status => :ok } format.html { respond_with resource, :location => after_sign_in_path_for(resource) } end end # DELETE /resource/sign_out def destroy redirect_path = after_sign_out_path_for(resource_name) signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)) set_flash_message :notice, :signed_out if signed_out && is_navigational_format? # We actually need to hardcode this as Rails default responder doesn''t # support returning empty response on GET request respond_to do |format| format.all { head :no_content } format.any(*navigational_formats) { redirect_to redirect_path } end end protected def sign_in_params devise_parameter_sanitizer.sanitize(:sign_in) end def serialize_options(resource) methods = resource_class.authentication_keys.dup methods = methods.keys if methods.is_a?(Hash) methods << :password if resource.respond_to?(:password) { :methods => methods, :only => [:password] } end def auth_options { :scope => resource_name, :recall => "#{controller_path}#new" } end end

esto es un formulario de registro

<%= form_for(:user, :html => {:id => ''register_form''}, :url => user_registration_path, :remote => :true, :format => :json) do |f| %> <div class="name_input_container"> <div class="name_input_cell"> <%= f.email_field :email, :placeholder => "email" %> <%= f.password_field :password, :placeholder => "password", :title => "8+ characters" %> <%= f.password_field :password_confirmation, :placeholder => "confirm password" %> <div class="option_buttons"> <div class="already_registered"> <%= link_to ''already registered?'', ''#'', :class => ''already_registered'', :id => ''already_registered'', :view => ''login'' %> </div> <%= image_submit_tag(''modals/account/register_submit.png'', :class => ''go'') %> <div class="clear"></div> </div> <% end %>


Ha olvidado agregar <%= csrf_meta_tags %> al costado de su archivo de diseño.

p.ej:

<!DOCTYPE html> <html> <head> <title>Sample</title> <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> <%= javascript_include_tag "application", "data-turbolinks-track" => true %> <%= csrf_meta_tags %> </head> <body> <%= yield %> </body> </html>


Para Rails 5 podría deberse al orden en que protect_from_forgery y tus before_actions se activan.

Me enfrenté a una situación similar recientemente, aunque protect_from_forgery with: :exception fue la primera línea en el ApplicationController , las before_action todavía estaban interfiriendo.

La solución fue cambiar:

protect_from_forgery with: :exception

a:

protect_from_forgery prepend: true, with: :exception

Hay una publicación en el blog aquí http://blog.bigbinary.com/2016/04/06/rails-5-default-protect-from-forgery-prepend-false.html


Según los comentarios en el núcleo application_controller.rb , establezca protect_from_forgery en lo siguiente:

protect_from_forgery with: :null_session

Alternativamente , según los documentos , simplemente declarar protect_from_forgery sin un argumento :with utilizará :null_session por defecto:

protect_from_forgery # Same as above

ACTUALIZAR :

Esto parece ser un error documentado en el comportamiento de Devise. El autor de Devise sugiere desactivar protect_from_forgery en la acción del controlador particular que está planteando esta excepción:

# app/controllers/users/registrations_controller.rb class RegistrationsController < Devise::RegistrationsController skip_before_filter :verify_authenticity_token, :only => :create end



TLDR: probablemente esté viendo este problema porque su formulario se envía a través de XHR.

Pocas cosas primero:

  1. Rails incluye un token CSRF dentro de la etiqueta principal de su página.
  2. Rails evalúa este token CSRF cada vez que realiza una solicitud POST, PATCH o DELETE.
  3. Este token caduca al iniciar o cerrar sesión

Un inicio de sesión HTTP estándar de pantano causará una actualización de página completa, y el token de CSRF antiguo se eliminará y se reemplazará por uno nuevo que Rails crea al iniciar sesión.

Un inicio de sesión de AJAX no actualizará la página, por lo que el antiguo token de CSRF obsoleto, que ahora no es válido, aún está presente en su página.

La solución es actualizar manualmente el token CSRF dentro de su etiqueta HEAD después de iniciar sesión en AJAX.

Algunos pasos que he tomado descaradamente de un hilo útil sobre este asunto .

Paso 1: Agregue el nuevo CSRF-token a los encabezados de respuesta que se envían después de un inicio de sesión correcto.

class SessionsController < Devise::SessionsController after_action :set_csrf_headers, only: :create # ... protected def set_csrf_headers if request.xhr? # Add the newly created csrf token to the page headers # These values are sent on 1 request only response.headers[''X-CSRF-Token''] = "#{form_authenticity_token}" response.headers[''X-CSRF-Param''] = "#{request_forgery_protection_token}" end end end

Paso 2: use jQuery para actualizar la página con los nuevos valores cuando se ajaxComplete evento ajaxComplete :

$(document).on("ajaxComplete", function(event, xhr, settings) { var csrf_param = xhr.getResponseHeader(''X-CSRF-Param''); var csrf_token = xhr.getResponseHeader(''X-CSRF-Token''); if (csrf_param) { $(''meta[name="csrf-param"]'').attr(''content'', csrf_param); } if (csrf_token) { $(''meta[name="csrf-token"]'').attr(''content'', csrf_token); } });

Eso es. YMMV dependiendo de su configuración Devise. Sin embargo, sospecho que este problema en última instancia es causado por el hecho de que el token viejo de CSRF está matando la solicitud y Rails lanza una excepción.