Usando la gema brazuca devise para autentificacación en Rails 4, sucede que además del mail y el pass, hay otros atributos que necesito guardar en la tabla users.
protected attributes
En Rails < 4 para ello bastaba con declararlos como attr_accessible >>, lo cual había hecho el desarrollador cuyo pato estoy pagando y para lo cual -sospecho- está importando la gema de esta funcionalidad deprecada
Gemfile:
gem 'protected_attributes'
user.rb:
class User < ActiveRecord::Base devise :registerable#etc attr_accessible :email, :password, :nombre, :largo_del_pelo #etc end
strong parameters
Como dije, attr_accessible fue deprecado en Rails 4 y ahora el filtro se hace a nivel del controlador, ésto es lo que se llama strong parameters. ¿Qué tiene que ver? Pues siga leyendo:
Con un poco de debug, vemos que el hash del que se arman los usuarios es sign_up_params
class Devise::RegistrationsController < DeviseController #... # POST /resource def create self.resource = build_resource(sign_up_params) if resource.save #.... end
los cuales no incluyen mis atributos
{"email"=>"1@example.com", "password"=>"password", "password_confirmation"=>"password"}
porque están ‘sanitizados’
def sign_up_params devise_parameter_sanitizer.for(:sign_up) end
Nótese que ésto es nuevo en el branch rails4, por lo que por aquí va la cosa, vea a continuación:
Este método está definido en lib/devise/controllers/helpers.rb, y soporta Strong Parameters
# Setup a param sanitizer to filter parameters using strong_parameters. See # lib/devise/controllers/parameter_sanitizer.rb for more info. Override this # method in your application controller to use your own parameter sanitizer. def devise_parameter_sanitizer @devise_parameter_sanitizer ||= if defined?(ActionController::StrongParameters) Devise::ParameterSanitizer.new(resource_class, resource_name, params) else Devise::BaseSanitizer.new(resource_class, resource_name, params) end end
Y he ahí la clave
Override this method in your application controller to use your own parameter sanitizer
i.e. el filtro lo está haciendo esta clase BaseSanitizer, y debo sobrescribirlo.
sobrescritura
Primero entenderlo un poco.. no me meteré en el método for, pero éste invoca a sign_up, como vimos, el cual tiene información decidora
def sign_up default_params.permit(auth_keys + [:password, :password_confirmation]) end
por tanto la primera tentación es añadir mis atributos simplemente en devise.rb (en mi app)
config.authentication_keys = [ :email , :nombre, :largo_de_pelo ]
con lo cual efectivamente los atributos se guardan pero, evidentemente, no me puedo loguear: tendría que hacer que el usuario escribiera estos atributos para ingresar.
Por tanto tendré que sobrescribir. Lo intentaré con el mismo método sign_up_params, el cual se encuentra en la misma clase de la que ya estoy heredando
class Users::RegistrationsController < Devise::RegistrationsController #etc protected def sign_up_params params.require(:user).permit(:email, :password, :password_confirmation, :nombre, :largo_de_pelo) end #... end
y funciona 🙂
Véase mi respuesta en Stack Overflow >>