User's Email Parameter Not Been Persisted Into The Database - ruby-on-rails

I created a users model in a rails 4.1.8 application with the attributes email and password. I fired up rails console, user = User.new(email: "user#example.com" , password: "example") work but user.save saves the password and omits the email. below is the model, migrated database file and rails console log.
USER MODEL
class User < ActiveRecord::Base
before_save {self.email = email.downcase! }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format:{with: VALID_EMAIL_REGEX},
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end
DATABASE FILE (For the User)
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, unique: true
t.string :password_digest
t.timestamps null: false
end
end
end
RAILS CONSOLE LOG
<r.new(email: "user#example.com" , password: "example")
=> #<User id: nil, email: "user#example.com", password_digest: "$2a$10$jxwd/oriT
z2HklHK4b4nf.P.DWb6s35YTO.EbYwup0I...", created_at: nil, updated_at: nil>
irb(main):008:0> user.save
(1.0ms) BEGIN
User Exists (1.0ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'user#example.com' LIMIT 1
SQL (46.0ms) INSERT INTO `users` (`created_at`, `password_digest`, `updated_at`) VALUES ('2015-07-20 20:54:35', '$2a$10$jxwd/oriTz2HklHK4b4nf.P.DWb6s35YTO.Eb
Ywup0I.gMTOLSNKa', '2015-07-20 20:54:35')
(89.1ms) COMMIT
=> true
USERS CONTROLLER
class UsersController < ApplicationController
def new
end
private
def user_params
params.require(:user).permit(:email)
end
end
Looking at the log the email parameter was not inserted into; please, any help with this is appreciated.

Try the following in your User model:
before_save {self.email = email.downcase } # no "!"
downcase! edits the variable on which it is called and does not return the downcased string unless there is something to downcase (i.e., if you use it on an all lower-case email, it returns nil and based on your console output, this is what is happening). downcase alone should be fine.
downcase! on the API

Related

Rails - Unknown attribute password

I have been following Michael Hartl's Ruby on Rails tutorial book to try and add users to my application. Reading chapter 6, I have added what I believe to be the necessary fields for my user, specifically password and password confirmation via "has_secure_password".
I thought that adding "has_secure_password" to my user model would include the attributes "password" and "password_confirmation" provided I add a "password_digest" to the model. I have done that as the book instructed me to. However, when I run a test, Rails gives me the following error:
Error:
UserTest#test_should_be_valid:
ActiveModel::UnknownAttributeError: unknown attribute 'password' for User.
test/models/user_test.rb:8:in `setup'
I tried this solution and it still gave me the same error, not recognizing the attributes "password" or "password_confirmation". I installed bcrypt using "gem install bcrypt" and included the following in my gem file:
gem 'bcrypt-ruby', :require => 'bcrypt'
I am using Rails 5 and it seems like "has_secure_password" is not supplying the password attributes that I need. Can anyone see what I missed or did wrong that caused "has_secure_password" to not work as intended? Thanks
User Model:
class User < ApplicationRecord
has_many :activities
class User < ActiveRecord::Base
attr_accessor :name, :email, :password, :password_confirmation
has_secure_password
validates :first_name, presence: true, length: {minimum: 1}
validates :last_name, presence: true, length: {minimum: 1}
validates :email, presence: true, uniqueness: true, length: {minimum: 5}
validates :username, presence: true, uniqueness: true, length: {minimum: 1}
validates :password_digest, length: {minimum: 6}
validates :password, :confirmation => true, length: {minimum: 4}
validates :password_confirmation, presence: true
#-----------------------New Stuff ---------------------------------------
acts_as_authentic do |c|
c.crypto_provider = Authlogic::CryptoProviders::Sha512
end
#------------------------------------------------------------------------
#---------------Unsure if working--------------
#validates_presence_of :password, :on => :create
#validates_presence_of :email
#validates_uniqueness_of :email
#----------------------------------------------
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
end
Apologies for the messy code on the model as I am still learning Rails.
User Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = 'Account created'
else
flash[:notice] ='ERROR: Account was not created'
redirect_to 'users/new'
end
end
def show
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
User Table:
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "persistence_token"
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
end
User Test:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
def setup
#user = User.new(first_name: 'test', last_name: 'tester', password: '1234',email: 'test1#mail.com',
password: 'foobar', password_confirmation: 'foobar')
end
test 'should be valid' do
assert #user.valid?
end
end
Update:
I have tested this out and it works. So hope will work for you as well :) Looks like MiniTest doesn't work well with BCrypt. I received the same error - undefined password, but later implemented my change and it went further well.
Original answer:
As of your founded solution it made me think that this makes no sence - adding getter and especially setter methods for :password and :password_confirmation. Because has_secure_password creates those virtually that runs through BCrypt. So doesn't it goes around crypting / encrypting? If so it is not safe. So only option left for testing I see take the BYcript into the testing suite. I think something like this might do the trck:
In User Test:
require 'bcrypt'
def setup
#user = User.new(first_name: 'test', last_name: 'tester', password: BCrypt::Password.create("my password") ,email: 'test1#mail.com', password_confirmation: 'my password')
end
test 'should be valid' do
assert #user.valid?
end
Note that I removed duplicated password: 'foobar. Since with that particular test you are testing if User can be created, so shouldn't pass a different password or even duplicated attribute... Make another test for this (also checkout fixtures, they are great for creating test objects, as well as factories for more complicated cases).
And of course, remove the atr_accessor :password, :password_confirmation form your User model.
p.s. and please fix you code snippet for User class. Or is it really defined twice like this?:
class User < ApplicationRecord
has_many :activities
class User < ActiveRecord::Base

Unable to update the record because of validation of name

namespace :send_query do
task :to_admins => :environment do
contacts = Contact.select(:name, :mobile, :company, :requirement).where(email_sent: false).distinct
if !contacts.blank?
contacts.each do |contact|
GuestMailer.query_email(contact.name,
contact.mobile,
contact.company,
contact.requirement).deliver
contact.update!(email_sent: true)
end
end
puts "done sending query emails"
end
end
I wrote a rake task to send emails. After sending email, I am updating the field email_sent to true. But the transaction is rolling back after sending email.
(0.2ms) BEGIN
Contact Exists (0.7ms) SELECT 1 AS one FROM "contacts" WHERE "contacts"."name" = $1 AND ("contacts"."id" IS NOT NULL) AND "contacts"."mobile" = $2 AND "contacts"."requirement" = $3 AND "contacts"."company" = $4 LIMIT $5 [["name", "vamsi pavan mahesh"], ["mobile", "9247474925"], ["requirement", "yo yo honey singhu"], ["company", "mahesh#bla.com"], ["LIMIT", 1]]
(0.2ms) ROLLBACK
rake aborted!
ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
Here is the Contact model
# == Schema Information
#
# Table name: contacts
#
# id :integer not null, primary key
# name :string
# mobile :string
# company :string
# requirement :text
# created_at :datetime not null
# updated_at :datetime not null
# email_sent :boolean default(FALSE)
#
class Contact < ApplicationRecord
validates :name, presence: true
validates :mobile, presence: true
validates :requirement, presence: true
validates_uniqueness_of :name, scope: [:mobile, :requirement, :company]
end
On your Contact model, you can do on: :create and that will only apply that validate on the create action.
validates :name, presence: true, on: :create
EDIT:
As MrYoshiji pointed out in the comments, it's the uniqueness validation on the name that is causing the validation error, so the fix would actually be:
validates :name, uniqueness: { scope: [:mobile, :requirement, :company] }, on: :create

Rails 5: ActiveRecord not creating record

I'm working on a modified version of Michael Hartl's Learn Rails Tutorial. I'm on chapter 6, modeling users. For some reason, my users aren't creating correctly on ActiveRecord and aren't saving at all.
I placed these users in my seeds.rb file
user_1 = User.create(id: 1, name: 'Han Solo', email: 'han#example.com')
user_2 = User.create(id: 2, name: 'Luke Skywalker', email: 'luke#example.com')
Then I run rails db:seed, but if I go to my rails console, it appears like no users have been created:
Running via Spring preloader in process 24358
Loading development environment (Rails 5.0.0.1)
2.2.2 :001 > User.delete_all
SQL (1.1ms) DELETE FROM "users"
=> 0
2.2.2 :002 >
user.rb User Model
class User < ApplicationRecord
#Ensure Email Uniqueness by Downcasing the Email Attribute
before_save {self.email = email.downcase }
#validates name, presence, and length
validates :name, presence: true, length: { maximum: 100 }
#Validate presence, length, format, and uniqueness (ignoring case)
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: {maximum: 250}, format: {with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
#Adds ability to save securely hashed password_digest attribute to database
#Adds a pair of virtual attributes (password and password_confirmation)
#including presence validations upon object creation and a validation
#requiring that they match
#adds authenticate method that returns the user when the password is correct (and false otherwise)
has_secure_password
PASSWORD_FORMAT = /\A
(?=.{8,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password, presence: true, length: {minimum: 8}, format: {with: PASSWORD_FORMAT}
end
schema.rb
ActiveRecord::Schema.define(version: 20161020211218) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
end
end
Anyone have any idea what might be going on?
Ok, I figured it out.
I took out id from the seeds.rb. When I took out the id attribute, it started throwing me the error of the user not having a valid password. I then added a password and password confirmation to conform to password standards set in my user model.
Updated my model and added a password confirmation.
Here's my updated user.rb
class User < ApplicationRecord
#Ensure Email Uniqueness by Downcasing the Email Attribute
before_save {self.email = email.downcase }
#validates name, presence, and length
validates :name, presence: true, length: { maximum: 100 }
#Validate presence, length, format, and uniqueness (ignoring case)
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: {maximum: 250}, format: {with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
#Adds ability to save securely hashed password_digest attribute to database
#Adds a pair of virtual attributes (password and password_confirmation)
#including presence validations upon object creation and a validation
#requiring that they match
#adds authenticate method that returns the user when the password is correct (and false otherwise)
has_secure_password
PASSWORD_FORMAT = /\A
(?=.{8,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password, presence: true, length: {minimum: 8}, format: {with: PASSWORD_FORMAT}
validates :password_confirmation, presence: true
end
And seeds.rb
user_1 = User.create!(name: 'Han Solo', email: 'han#example.com', password: 'Password123!', password_confirmation: 'Password123!')
user_2 = User.create!(name: 'Luke Skywalker', email: 'luke#example.com', password: 'Password123!', password_confirmation: 'Password123!')
I tested that the user is being created properly by opening up the rails console, running User.delete_all , and seeing them wiped off the SQL record.

Ruby on Rails - User object showing nil fields even though they are filled

I'm having a weird problem with getting my user registration to work in Rails. When I create a user, it will show all its fields but the password_digest being nil, but when I type something like "u.email", the email will show up. However, it doesn't want to save the user, I assume because it thinks it doesn't meet all the validation requirements.
Some rails console fiddling:
irb(main):003:0> u = User.new({username: "askddkasd", email: "a#a.a",
password: "meowmeowmeow", password_confirmation: "meowmeowmeow"})
=> #<User id: nil, username: nil, email: nil, password_digest:
"$2a$10$eWhQdOCLXfmcGrrRdigSFeENUeAEaQ6xJ7U08k7g3gZ...", salt: nil>
irb(main):002:0> u.save
(0.2ms) BEGIN
User Exists (0.3ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'askddkasd' LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'a#a.a' LIMIT 1
(0.1ms) ROLLBACK
=> false
irb(main):022:0> u.username
=> "askddkasd"
irb(main):023:0> u.email
=> "a#a.a"
As you can see, the fields appear nil, but I can access their values.
Here is my user model:
class User < ApplicationRecord
has_secure_password
attr_accessor :username, :email, :password, :password_confirmation
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true
validates :password, :confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
after_save :clear_password
def password=(password)
self.password_digest = BCrypt::Password.create(password)
end
def is_password?(password)
BCrypt::Password.new(self.password_digest) == password
end
def clear_password
self.password = nil
end
def self.authenticate(username_or_email="", login_password="")
if username_or_email.include? '#'
user = User.find_by_email(username_or_email)
else
user = User.find_by_username(username_or_email)
end
if user && user.is_password?(login_password)
return user
end
return false
end
end
Has anyone had this problem before? If so, how did you resolve it?
Update: Could it be because I have username and email as accessors? So those values don't actually get to the username/email fields to be stored in the database?
The fact that it rolls back after this statement in the log
User Exists (0.2ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'a#a.a' LIMIT 1
makes me think that there is already a user in the database with this email address. You can figure out for sure what the issue is by calling u.valid? and then u.errors.

Rollback Transaction Error - Rails

A few classmates and I are having some trouble in our Rails app for class. Whenever we try to user the User.create for a RoR app on the rails console, we get a rollback transaction after we complete the necessary form.
Any way to fix this? Here is the error:
rails console
Loading development environment (Rails 3.2.13)
irb(main):001:0> User.count
(0.0ms) SELECT COUNT(*) FROM "users"
=> 0
irb(main):002:0> User.create(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('rush#example.com') LIMIT 1
(0.0ms) rollback transaction
=> #<User id: nil, name: "Mr Rush", email: "rush#example.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$quwMA.4fcrBpg2sRy00qEOWrjHduAN0OZFvcXiCmNjUR...">
irb(main):003:0>
User.rb file
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = user.email.downcase }
validates :name, presence: true, length: {maximum: 30}
VALID_EMAIL_REGEX = /\A[\w+\-\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 5 }
validates :password_confirmation, presence: true
end
Your user is failing to create because the email is failing the format validation.
It's interesting though that it reports this error as if the uniqueness is the thing causing the problem. You have shown your user table to be empty so no way it can fail a uniqueness constraint.
A couple of things to try:
1) in the console try this:
user = User.new(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
user.valid? <--- should give you false
user.errors <--- should tell you the format of the email is incorrect
When I combine presence with anything else in a validator I always allow the value to be blank in the following validations; there is no point in validating the format or uniquessness of something if it is mandatory but missing. i.e.
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX, allow_blank: true}, uniqueness: { case_sensitive: false, allow_blank: true }
Doing this may or may not change what it thinks the real validation failure is.
2) fix the regex for email validation. Validating email address by regex is a bit controversial, but you should find something like this will work:
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
You can always try out the regex validation using a website like Rubular.
User.create(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
When running into this while doing Michael Hartls Rails Tutorial this example will fail because the password fubar is too short, as set to minimum: 6 in Listing 6.39. The console is really less than verbose here.

Resources