at.
at.

Reputation: 52540

Seeding users with Devise in Ruby on Rails

In my development and test environments, I want to seed the database with a bunch of users. I'm using Ruby on Rails v3.2.8 and the latest Devise. So I added this line in my db/seeds.rb file:

User.create(email: '[email protected]', encrypted_password: '#$taawktljasktlw4aaglj')

However, when I run rake db:setup, I get the following error:

rake aborted! Can't mass-assign protected attributes: encrypted_password

What is the proper way to seed users?

Upvotes: 37

Views: 42651

Answers (15)

jpa57
jpa57

Reputation: 11

In a Rails 3 User model I have, there are several more required fields. Combining other advice here and elsewhere, I built an export rake task that creates a seeds.rb that works with devise on the receiving side in Rails 5. It first lets Devise do its thing encrypting a bogus password, then saves the user's original encrypted password. Note the methods parameter to .serializable_hash, without which these fields don't get serialized.

namespace :export do
  desc "Export users"
  task :seeds => :environment do
    # Dependent models loaded first
    User.all.each do |user|
      excluded_keys = ['invitation_sent_at', 'invitation_accepted_at', 'invitation_created_at']
      serialized = user
                    .serializable_hash(methods: [:encrypted_password, :sign_in_count])
                     .delete_if{|key,value| excluded_keys.include?(key)}
      serialized['password'] = '123456789ABCDefg%'
      serialized['password_confirmation'] = '123456789ABCDefg%'
      puts "user = User.new(#{serialized})"
      puts "user.save!"
      puts "user.encrypted_password = '#{user.encrypted_password}'"
      puts "user.save!"
    end
  end
end

I ran that with rake export:seeds. I also had to change user.rb to bypass some serialization that Devise is doing on dates. I didn't bother doing this with the invitation dates because they were nullable and the bypass wasn't working. I took the 'serialize' lines back out after generating the seeds.rb, since I wasn't sure what the consequences might be. Relevant lines here:

class User < ActiveRecord::Base 
  devise :timeoutable, :timeout_in => 6.hours
  devise :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  serialize :created_at, DateTime
  serialize :updated_at, DateTime

Upvotes: 0

jfgilmore
jfgilmore

Reputation: 85

Don't try create the encrypted password, devise handles that for you. This will work, just make sure the password is a minimum 6 characters long.

User.create(
        email: "[email protected]",
        password: "123456"
    )

Even better, in your terminal:

$bundle add faker

Then:

User.create(
            email: [email protected],
            password: "123456"
        )
10.times do
  User.create(
              email: Faker::Internet.email,
              password: "123456"
           )
end

Just make sure you set at least one email in your seeds that you can remember. Hence retaining the 'test' email.

Upvotes: 2

Muhammad Sannan Khalid
Muhammad Sannan Khalid

Reputation: 3137

The skip_confirmation method will only work if you have confirmable module in your user model, otherwise remove it.

  user = User.new(
      :email                 => "[email protected]",
      :password              => "123456",
      :password_confirmation => "123456"
  )
  user.skip_confirmation!
  user.save!

Upvotes: 16

Leonel Sanches da Silva
Leonel Sanches da Silva

Reputation: 7220

This allows you to run a seed multiple times without errors:

User.where(email: "[email protected]").first_or_create.update_attributes(nome: "Your Name",
    email: "[email protected]",
    password:              "password#123",
    password_confirmation: "password#123")

Upvotes: 0

Bilal A.Awan
Bilal A.Awan

Reputation: 398

Just add :password attribute rest, devise will do password_encrypt for you

user = User.new({ email: '[email protected]', password: 'EnterYourPassword'})
user.save!
flash[:notice] = 'User Created'

#or for extra logic

        #if user.save
          #ExtraCredentialsOrLogic

        #elsif user.errors.any?
          #user.errors.full_messages.each do |msg|
            #puts msg
          #end
        #else
          #puts "****NOT VALID****"
    #end

and now run 'rake db:seed'

Upvotes: 0

vidur punj
vidur punj

Reputation: 5871

with email confirmating in db:seed :

User.create!( name: 'John', email:'[email protected]', password: '123456', password_confirmation: '123456',confirmed_at: '2018-08-04 04:51:43', current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1")

Upvotes: 0

lacostenycoder
lacostenycoder

Reputation: 11226

For devise users in seeds.rb file, what worked for me was to use a generic password upon saving the new user. Then update the encrypted password and save the model again. This was a hacky way.

user = User.new(
    :email                 => "[email protected]",
    :password              => "fat12345",
    :password_confirmation => "fat12345"
)
user.save!
user.encrypted_password="ENCRYPT.MY.ASS!!!KJASOPJ090923ULXCIULSH.IXJ!S920"
user.save

UPDATE others have posted and this is better way to do it:

user = User.new(
    email: "[email protected]", 
    password: "foob1234", 
    password_confirmation: "foob1234"
)
user.skip_confirmation! #only if using confirmable in devise settings in user model.
user.save!

Upvotes: 1

alexventuraio
alexventuraio

Reputation: 10114

I don't know if it may help but actually I'm doing this to create a default Admin user in my Rails 5 app but without sharing the password in plain text in my GitHub repository.

Basically the logic for this is:

  • Generate a secure random password for the default user when seeded.
  • Go to ".../admins/sign_in" and click on "Forgot your password?" link to RESET it.
  • Get the reset password link in that default email account.
  • Set a new password.

So in the db/seeds.rb append this:

randomPassword = Devise.friendly_token.first(8)
mainAdminUser = Admin.create!(email: "[email protected]", password: randomPassword, name: "Username")

And if you are using devise confirmable feature just skip confirmable option by doing this:

mainAdminUser = Admin.new(
    email: "[email protected]",
    password: randomPassword,
    password_confirmation: randomPassword,
    name: "Username"
)
mainAdminUser.skip_confirmation!
mainAdminUser.save!

And your good to go!

Now you have a default user but you are not sharing a default password! I hope it could be useful for somebody.

Upvotes: 4

Victor
Victor

Reputation: 5121

If you're using the devise confirmable module you need to do something like:

user = User.new(
  email: '[email protected]', 
  password: '123456789', 
  password_confirmation: '123456789'
)
user.skip_confirmation!
user.save!

The skip_confirmation! call just tell to devise that you don't need to confirm this account.
Other option is just set the confirmed_at user attribute as Time.now.utc before save.

Upvotes: 8

doncadavona
doncadavona

Reputation: 7760

To seed the users table:

User.create(
        email: "[email protected]",
        password: "12345678"
    )

With devise installed, the :password will be automatically hashed and saved to :encrypted_password

Upvotes: 4

Koxzi
Koxzi

Reputation: 1051

This is an old question but here is an example with an admin user (from cancancan):

User.create!([
  {email: "[email protected]", password: "testadminuser", password_confirmation: "testadminuser", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-02-06 14:02:10", last_sign_in_at: "2015-02-06 14:02:10", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: true},
  {email: "[email protected]", password: "testuseraccount", password_confirmation: "testuseraccount", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-02-06 14:03:01", last_sign_in_at: "2015-02-06 14:03:01", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: false},
  {email: "[email protected]", password: "testcustomeruser", password_confirmation: "testcustomeruser", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-02-06 14:03:44", last_sign_in_at: "2015-02-06 14:03:44", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: false}
])

Upvotes: 8

aloucas
aloucas

Reputation: 3037

Use your db/seeds.rb file to initiate your first user:

User.create!(email: '[email protected]', 
             password: '123456789', 
             password_confirmation: '123456789')

Upvotes: 1

AnkitG
AnkitG

Reputation: 6568

I Did something same in one of my requirements so just pasting my snippet

def triggerSeedUsers
      p "Starting Seeding Users..."
      p   "Deleting all users"..
      User.destroy_all
      normal_users = [{:email => '[email protected]', :login => "abc_demo", :name => 'abc Demo'}]
      admin_users = [{:email => '[email protected]', :login => 'abc_admin', :name => 'abc Admin'}]

      [normal_users,admin_users].each do |user_type|
        user_type.each do |user|
          User.create!(:name => user[:name],
            :login => user[:login],
            :email => user[:email],
            :first_login => false,
            :password => 'P@ssw0rd',
            :password_confirmation => 'P@ssw0rd'
            )
        end
      end
      User.where('name LIKE ?', '%demo%').update_all(:is_admin => 0)
      User.where('name LIKE ?', '%admin%').update_all(:is_admin => 1)
     end

Upvotes: 0

George
George

Reputation: 668

Arun is right. It's easier just to do this in your seeds.rb

user = User.create! :name => 'John Doe', :email => '[email protected]', :password => 'topsecret', :password_confirmation => 'topsecret'

Upvotes: 31

Arun Kumar Arjunan
Arun Kumar Arjunan

Reputation: 6857

You have to do like this:

user = User.new
user.email = '[email protected]'
user.encrypted_password = '#$taawktljasktlw4aaglj'
user.save!

Read this guide to understand what mass-assignment is: http://guides.rubyonrails.org/security.html

I am wondering why do have to directly set the encrypted password. You could do this:

user.password = 'valid_password'
user.password_confirmation = 'valid_password'

Upvotes: 51

Related Questions