fade2black
fade2black

Reputation: 614

Devise and User.create

Usually when we create a model, say User, its attributes match with database fields. For example, if my corresponding database table users_development has fields name and score then when I create an instance of the User class I simply type user = User.create(:name => "MyName", :score => 85).

Now, Devise created a migration file including fields email and encrypted_password, but I cannot see the field password (which is quite logically from the security point of view).

While looking through forum posts I saw many examples like User.create(:email =>"[email protected]", :password => "foo"). So, where did the password come from? It is not a field of table users_development. What is going on behind the scene? I looked through the documentation on http://rubydoc.info/github/plataformatec/devise/master/Devise but couldn't find any explanation.

Upvotes: 0

Views: 84

Answers (2)

Intrepidd
Intrepidd

Reputation: 20948

This method from devise source code does the trick :

# Generates password encryption based on the given value.
 def password=(new_password)
   @password = new_password
   self.encrypted_password = password_digest(@password) if @password.present?
 end

When calling create, update attributes, build, etc, rails will try to call for each field the method field=, so when you pass :password => 'foo' to create it will do something like :

user = User.new
user.password = 'foo'
user.save

Here this method allows to build the model with an unhashed password but to store the hashed password in the database.

Upvotes: 2

Dylan Markow
Dylan Markow

Reputation: 124469

User.create(:email => "[email protected]", :password => "foo") does not directly create a database record with those exact fields. Rather, it uses public_send("#{k}=", v) for each pair in the parameters hash. So really, it's doing something like this internally:

user = User.new
user.email = "[email protected]"
user.password = "foo"
user.save

Even though you don't have a password database field, Devise's DatabaseAuthenticatable module adds a password= method, which updates the encrypted_password field:

def password=(new_password)
  @password = new_password
  self.encrypted_password = password_digest(@password) if @password.present?
end

Upvotes: 3

Related Questions