I'm testing some associations after adding a new migration that associates users to many posts.
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Customization
t.string :name
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
After I migrated, I'm supposed to test with
u = User.first
to receive this block of code make sure everything is running smoothly.
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, name: nil, email: "username#example.com", encrypted_password: "$2a$10$702fd8Io3WH7UTWoTY3rUeUJBcFVlsq8/K6ypPKZUQni...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: "2013-04-29 20:25:26", confirmation_sent_at: "2013-04-29 20:25:09", unconfirmed_email: nil, created_at: "2013-04-29 20:25:09", updated_at: "2013-04-29 20:25:26">
but I got nil
2.1.5 :001 > u = User.first
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> nil
Is this a bad thing? Why isn't anything showing up?
Your database is empty at present. And hence you are getting a nil. You can do this:
1) Add a new user to the table using devise sign-up functionality in the front end.
2) Add seed data in the db/seeds.rb file like this:
User.find_or_create_by(:email => 'tester#test.com', :password => 'password', :password_confirmation => 'password')
Run rake db:seed from command prompt. Seeds data is the initial data that you want to add to your database for the application to run as desired.
3) Use Rails console: Run rails c in your command prompt and do this:
User.create(:email => 'tester#test.com', :password => 'password', :password_confirmation => 'password')
You need to do something like this in your console to add the first user:
user = User.new(:email => 'tester#test.com', :password => 'testingpassword',
:password_confirmation => 'testingpassword')
user.save
Devise doesn't create a default user for you, so until you create one, user.first wil come back as nil
Related
I am trying to use Devise on my User model but when I go into rails console and try User.new I only get:
irb(main):002:0> User.new
=> #<User id: nil, first_name: nil, last_name: nil, email: nil, created_at: nil, updated_at: nil>
Why are the devise columns not showing up?
CreateUsers migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.timestamps null: false
end
end
end
AddDeviseToUsers migration:
class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
# Uncomment below if timestamps were not included in your original model.
# t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
def self.down
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
raise ActiveRecord::IrreversibleMigration
end
end
Schema shows the columns are there:
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
Any ideas?
It's a security feature that Devise has in order to restrict its attributes and the critical information it contains to be exposed to API calls.
You can however override this, you need to override serializable_hash method.
# app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable, :confirmable, :rememberable, :validatable
...
protected
def serializable_hash(options = nil)
super(options).merge(encrypted_password: encrypted_password, reset_password_token: reset_password_token) # you can keep adding attributes here that you wish to expose
end
end
You can check http://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Authenticatable where a constant is declared to blacklist attributes
BLACKLIST_FOR_SERIALIZATION =[:encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at, :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
Hope this answers your question!
If all you want to do it list all the attributes in the Rails console, it is easier to use User.first.serializable_hash(force_except: true)
See http://www.rubydoc.info/github/plataformatec/devise/Devise%2FModels%2FAuthenticatable:serializable_hash
Devise overrides the inspect method to not expose internal attibutes. You can try:
User.new.attributes
or
User.new.encrypted_password
(or whatever attribute you want)
You can check inspect method here
I'm trying to query my Devise-created table with find_by_sql and am running into a strange error.
User.find_by_sql("select username from user")
results in:
PG::UndefinedColumn: ERROR: column "username" does not exist
LINE 1: select username from user
: select username from user
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:
column "username" does not exist
LINE 1: select username from user
^
: select username from user
Here's my devise migration (I added the username field):
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :username, null: false
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
end
end
As you can see I have declared the field username. Querying other tables in this manner works perfectly. I have also tried User.find_by_sql("select 'username' from user"), and that just returns [#<User id: nil>].
Thanks!
Edit: want to add that User.last returns
#<User id: 1, username: "xxxxxx", email: "xxxxxxxx",
encrypted_password: "xxxxxx", reset_password_token: nil,
reset_password_sent_at: nil, remember_created_at: nil,
sign_in_count: 2, current_sign_in_at: "2016-06-26 20:16:59",
last_sign_in_at: "2016-06-25 22:00:31", current_sign_in_ip: "xxxxx",
last_sign_in_ip: "xxxx", created_at: "2016-06-25 22:00:31",
updated_at: "2016-06-26 20:16:59">
with the correct values in place of 'xxxxx'
It should be because the name of the table is users rather than user. You can check schema.rb to check that the name of table is users or user. However, according to the migration, it has to be users.
This should work: User.find_by_sql("select username from users"). And you can use User.find_by_sql("select id, username from users") if you need user_id of record along with the username.
Or rather I would suggest you to do it in the ruby way: User.select(:username)
Hope it Helps : )
I'm new to programming and have been learning Ruby on Rails for about 11 weeks.
When trying to test my user factory for validation, I get
1) User has a valid factory
Failure/Error: expect(#user.valid?).to eq(true)
expected: true
got: false
(compared using ==)
I'm using Devise for my user model, and FactoryGirl for my factories.
Here is my user factory:
FactoryGirl.define do
factory :user do
name "John Fahey"
sequence(:email, 100) { |n| "person#{n}#example.com" }
password "password"
password_confirmation "password"
confirmed_at Time.now
end
end
...and here is my spec
require 'rails_helper'
describe User do
before do
#user = build(:user)
end
it "has a valid factory" do
expect(#user.valid?).to eq(true)
end
end
I've been working on getting this spec to pass for a while now. For a while I was getting the "email already taken" error and I've gotten past that. I even got the spec to pass once, but I was using the now deprecated "should be" syntax. When I go to the correct ":expect" syntax I get this error. Does anyone have an idea of what I'm doing wrong here?
Here is my model
class User < ActiveRecord::Base
#== schema information.
# create_table "users", force: true do |t|
# t.string "name"
# t.string "email", default: "", null: false
# t.string "encrypted_password", default: "", null: false
# t.string "reset_password_token"
# t.datetime "reset_password_sent_at"
# t.datetime "remember_created_at"
# t.integer "sign_in_count", default: 0, null: false
# t.datetime "current_sign_in_at"
# t.datetime "last_sign_in_at"
# t.string "current_sign_in_ip"
# t.string "last_sign_in_ip"
# t.string "confirmation_token"
# t.datetime "confirmed_at"
# t.datetime "confirmation_sent_at"
# t.string "unconfirmed_email"
# t.datetime "created_at"
# t.datetime "updated_at"
# end
# add_index "users", ["email"], name: "index_users_on_email", unique: true
# add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
has_one :list
has_many :items, through: :list
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
end
here is what I see when I create a user instance in the rails console and test for errors:
2.0.0-p576 :004 > #user = User.create
(0.2ms) begin transaction
(0.2ms) rollback transaction
=> #<User id: nil, name: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_coun
t: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sen
t_at: nil, unconfirmed_email: nil, created_at: nil, updated_at: nil>
2.0.0-p576 :005 > #user.save
(1.0ms) begin transaction
(0.1ms) rollback transaction
=> false
2.0.0-p576 :006 > puts(#user.errors)
#<ActiveModel::Errors:0xa7cff88>
=> nil
2.0.0-p576 :007 >
When i print the error messages, I get
2.0.0-p576 :007 > puts(#user.errors.messages)
{:email=>["can't be blank"], :password=>["can't be blank"]}
=> nil
here's something interesting. Just to make sure, I did a rake db:migrate, and a rake db:test:prepare. The test passed. Then I did the exact test again, and it failed.
vagrant#rails-dev-box:~/code/blocitoff$ rake db:migrate
vagrant#rails-dev-box:~/code/blocitoff$ rake db:migrate
vagrant#rails-dev-box:~/code/blocitoff$ rake db:test:prepare
vagrant#rails-dev-box:~/code/blocitoff$ rspec spec/models/user_spec.rb
#<ActiveModel::Errors:0xbdf0740>
.
Finished in 0.1764 seconds (files took 8.96 seconds to load)
1 example, 0 failures
vagrant#rails-dev-box:~/code/blocitoff$ rspec spec/models/user_spec.rb
#<ActiveModel::Errors:0xa97066c>
F
Failures:
1) User has a valid factory
Failure/Error: expect(#user.valid?).to eq(true)
expected: true
got: false
(compared using ==)
Your email attribute needs to be unique and you're not cleaning your database between tests, so you're getting on error on second and subsequent executions of your test. See https://relishapp.com/rspec/rspec-rails/docs/transactions to learn about use of transactions in RSpec.
Just to package what Peter said, I was able to solve my problem by adding this setting to my spec_helper.rb.
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
I'm absolutely new to Rails, I nearly do not know what I am doing. But. The problem is: signing up new user with Devise results in:
SQLite3::ConstraintException: column email is not unique:
INSERT INTO "users" ("created_at","encrypted_password", "name", "updated_at")
VALUES (?, ?, ?, ?)
And the request parameters:
{"utf8"=>"✓",
"authenticity_token"=>"1bgk4ovS3JitphVkIvcCZi3ex8QsBq4eEf6ZihQLiHg=",
"user"=>{"name"=>"Someone",
"email"=>"8#prosto.me",
"password"=>"[FILTERED]"},
"commit"=>"Sign up"}
User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable;
end
DB migration:
class DeviseCreateUsers < ActiveRecord::Migration
def self.up
change_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :name, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
# Uncomment below if timestamps were not included in your original model.
# t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :name, :unique => true
add_index :users, :reset_password_token, :unique => true
# add_index :users, :confirmation_token, :unique => true
# add_index :users, :unlock_token, :unique => true
# add_index :users, :authentication_token, :unique => true
end
def self.down
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
end
end
Please tell me if I need to provide any other code.
And thank you for all your help in advance.
Update with DB schema:
ActiveRecord::Schema.define(version: 20131012114812) do
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Update 2: And there is also a problem with authentication. Devise tells 'Invalid email or password' for any previously successfully signed up user in attempt to login.
SQLite is telling you that it's trying to create a new record, where one of the values will be an email, but there is already an existing record with that email.
An easy way to read your database records is query the DB in a terminal window:
$ rails console
$ User.all
If you want to see your test DB, which will be loaded with your fixtures:
$ rails console -e=test
$ User.all
Look for records that have the same email of the one you're trying to create.
If this is your first time using Devise, you should check your fixtures. Devise currently defaults to two fixtures that have no attributes. If you're running in a test environment then those fixtures will be loaded into the test DB as a two records with nil values for email, which are duplicate email values. Fixtures like the ones below will get you passed your error message.
file: app/test/fixtures/users.yml
one:
email: user#example.com
encrypted_password: password1
two:
email: user2#example.com
encrypted_password: password2
Do you have any other "email" columns in that database?
Perhaps you already had a "users" table, where the email column has been replicated with Devise. It would be helpful if you could show us which columns your table has :)
Try adding a uniqueness validation to your User model:
validates_uniqueness_of :email, :allow_blank => true
This will re-render your user creation form instead of causing an error.
I pushed my to do list application to github.
Nor users, nor admins are created. The db is not uploaded to github (and should not).
so I should add all initial setup to db/seeds.rb to ensure that all db expectations are in place.
In addition, the Roles are not created in the seeds file, so the application fails to register users.
I tried to add all initial setup to db/seeds.rb:
Role.create({name: "Admin"})
Role.create({name: "Woeker"})
user1 = User.create!(
email: "admin2#gmail.com",
password: "12345678",
password_confirmation: "12345678"
encrypted_password: "$2a$10$7aK4tZTsCDB64qQI/kl.d.nZGwjEJPh7YlUNE8/Ty.0JhAMS.ALX6"
role_ids = [1]
)
user2 = User.create!(
email: "worker2#gmail.com",
password: "12345678",
password_confirmation: "12345678"
encrypted_password: "$2a$10$7aK4tZTsCDB64qQI/kl.d.nZGwjEJPh7YlUNE8/Ty.0JhAMS.ALX6"
role_ids = [2]
)
(the encrypted_password was taken from the rails console: u = user.last..)
Unfortunately, I'm not sure If I added all what I have to, and if I did it exactly.
in the page of localhost:3000/users/sign_up, I have to enter: Email, Password and Password confirmation.
These are the migrations:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
class Roles < ActiveRecord::Migration
def self.up
create_table :roles do |t|
t.string :name
t.timestamps
end
end
def self.down
drop_table :roles
end
end
class UserRoles < ActiveRecord::Migration
def self.up
create_table :roles_users, :id => false do |t|
t.references :role, :user
end
end
def self.down
drop_table :roles_users
end
end
Any help appreciated!
UPDATE: THIS IS THE SOLUTION?
Role.create({name: "Admin"})
Role.create({name: "Woeker"})
user1 = User.create!(
email: "admin2#gmail.com",
password: "12345678",
password_confirmation: "12345678"
role_ids = [1]
)
user2 = User.create!(
email: "worker2#gmail.com",
password: "12345678",
password_confirmation: "12345678"
role_ids = [2]
)
I have something like that. Remove the password confirmation. Do exactly as if you were in the sign in form.