英文:
Why is setting password_digest working in my Rails console but not via controller logic?
问题
I'm practicing some Rails authentication from scratch (sans Devise gem), but having a few issues for some reason implementing ActiveModel::SecurePassword
. If I go into console I'm able to create a fresh user, see all the validations enforced, and if I save a new user (e.g, user.save
), I see password_digest
successfully set.
However, if I create a new User via my user registration form, my password_digest
is nil
every time. Anyone know why? I know for sure my params are being received, as I can print them before saving and see them.
For context, here's what I've tried:
- Added
ActiveModel::SecurePassword
to my user model - Enabled
bcrypt
gem and ranbundle install
- If I go into
irb
, I'm able to generate a new instance fine like so and see thepassword_digest
:
3.2.1 :137 > new_user = User.new(first_name: "test", last_name: "tester", email: "foo@bar.com", password: "123123123")
=> #<User:0x0000000107c5bf40 id: nil, first_name: "test", last_name: "tester", email: "foo@bar.com", password: nil, created_at: nil, updated_at: nil>
3.2.1 :138 > new_user.save
TRANSACTION (0.7ms) BEGIN
User Exists? (0.8ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "foo@bar.com"], ["LIMIT", 1]]
User Create (0.5ms) INSERT INTO "users" ("first_name", "last_name", "email", "password", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["first_name", "test"], ["last_name", "tester"], ["email", "foo@bar.com"], ["password", "[FILTERED]"], ["created_at", "2023-03-07 03:36:07.501992"], ["updated_at", "2023-03-07 03:36:07.501992"]]
TRANSACTION (1.3ms) COMMIT
=> true
3.2.1 :139 > new_user.password_digest
=> "$2a$12$aIcAuAdSnJhrLw0bWHTh1OgTTmUioB2ra3h12cFNs/IwnJdyRYJEW"
# NOTE:^ Successfully encrypts the password field via Bcrypt
However, if I run through my registration form, all the params are correct, I get nil
for this field. Here's an irb
printout from latest user created from registration form:
3.2.1 :140 > latest_user = User.last
User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<User:0x0000000107d75ca0 id: 27, first_name: "Allday", last_name: "Everyday", email: "allday@everyday.com", password: nil, created_at: Tue, 07 Mar 2023 03:39:13.986217000 UTC +00:00, updated_at: Tue, 07 Mar 2023 03:39:13.986217000 UTC +00:00>
3.2.1 :141 > latest_user.password_digest
=> nil
# NOTE: digest is `nil`!
For reference, here's my current User model and my user_controller.rb
logic:
user.rb
# == Schema Information
#
# Table name: users
#
# id :bigint not null, primary key
# email :string
# first_name :string
# last_name :string
# password :string
# password_digest :string
# created_at :datetime not null
# updated_at :datetime not null
#
class User < ApplicationRecord
include ActiveModel::SecurePassword
has_secure_password
has_secure_password :recovery_password, validations: false
before_save :downcase_email
validates :email, format: {with: URI::MailTo::EMAIL_REGEXP}, uniqueness: true, presence: true
validates :first_name, length: {minimum: 2, maximum: 100}, presence: true
validates :last_name, length: {minimum: 2, maximum: 100}, presence: true
validates :password, length: {minimum: 8, maximum: 25}, presence: true
attr_accessor :password_digest, :recovery_password_digest
private
def downcase_email
self.email = email.downcase
end
end
And here's my controller logic:
user_controller.rb
class UserController < ApplicationController
# post '/user/register'
def create
user = User.new(user_params)
begin
user.save!
session[:user_id] = user.id
return render json: {success: true, status: 200}
rescue => exception
return render json: {success: false, status: 422, error: exception.message}
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
英文:
I'm practicing some Rails authentication from scratch (sans Devise gem), but having a few issues for some reason implementing ActiveModel::SecurePassword
. If I go into console I'm able to create a fresh user, see all the validations enforced, and if I save a new user (e.g, user.save
), I see password_digest
successfully set.
However, if I create a new User via my user registration form, my password_digest
is nil
every time. Anyone know why? I know for sure my params are being received, as I can print them before saving and see them.
For context, here's what I've tried:
- Added
ActiveModel::SecurePassword
to my user model - Enabled
bcrypt
gem and ranbundle install
- If I go into
irb
, I'm able to generate a new instance fine like so and see thepassword_digest
:
3.2.1 :137 > new_user = User.new(first_name: "test", last_name: "tester", email: "foo@bar.com", password: "123123123")
=> #<User:0x0000000107c5bf40 id: nil, first_name: "test", last_name: "tester", email: "foo@bar.com", password: nil, created_at: nil, updated_at: nil>
3.2.1 :138 > new_user.save
TRANSACTION (0.7ms) BEGIN
User Exists? (0.8ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "foo@bar.com"], ["LIMIT", 1]]
User Create (0.5ms) INSERT INTO "users" ("first_name", "last_name", "email", "password", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["first_name", "test"], ["last_name", "tester"], ["email", "foo@bar.com"], ["password", "[FILTERED]"], ["created_at", "2023-03-07 03:36:07.501992"], ["updated_at", "2023-03-07 03:36:07.501992"]]
TRANSACTION (1.3ms) COMMIT
=> true
3.2.1 :139 > new_user.password_digest
=> "$2a$12$aIcAuAdSnJhrLw0bWHTh1OgTTmUioB2ra3h12cFNs/IwnJdyRYJEW"
# NOTE:^ Successfully encrypts the password field via Bcrypt
However, if I run through my registration form, all the params are correct, I get nil
for this field. Here's an irb
printout from latest user created from registration form:
3.2.1 :140 > latest_user = User.last
User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<User:0x0000000107d75ca0 id: 27, first_name: "Allday", last_name: "Everyday", email: "allday@everyday.com", password: nil, created_at: Tue, 07 Mar 2023 03:39:13.986217000 UTC +00:00, updated_at: Tue, 07 Mar 2023 03:39:13.986217000 UTC +00:00>
3.2.1 :141 > latest_user.password_digest
=> nil
# NOTE: digest is `nil`!
For reference, here's my current User model and my user_controller.rb
logic:
user.rb
# == Schema Information
#
# Table name: users
#
# id :bigint not null, primary key
# email :string
# first_name :string
# last_name :string
# password :string
# password_digest :string
# created_at :datetime not null
# updated_at :datetime not null
#
class User < ApplicationRecord
include ActiveModel::SecurePassword
has_secure_password
has_secure_password :recovery_password, validations: false
before_save :downcase_email
validates :email, format: {with: URI::MailTo::EMAIL_REGEXP}, uniqueness: true, presence: true
validates :first_name, length: {minimum: 2, maximum: 100}, presence: true
validates :last_name, length: {minimum: 2, maximum: 100}, presence: true
validates :password, length: {minimum: 8, maximum: 25}, presence: true
attr_accessor :password_digest, :recovery_password_digest
private
def downcase_email
self.email = email.downcase
end
end
And here's my controller logic:
user_controller.rb
class UserController < ApplicationController
# post '/user/register'
def create
user = User.new(user_params)
begin
user.save!
session[:user_id] = user.id
return render json: {success: true, status: 200}
rescue => exception
return render json: {success: false, status: 422, error: exception.message}
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
Anyone see anything I'm doing that's wrong or have any suggestions on why password_digest
might be null when creating a User via controller method logic? Thanks so much for all of your time--been stumped on this one!
答案1
得分: 1
从您的 app/models/user.rb
文件中删除以下行:
attr_accessor :password_digest, :recovery_password_digest
因为attr_accessor
创建的getter和setter方法将覆盖Ruby on Rails自动为数据库中的列创建的方法。
英文:
Remove this line from your app/models/user.rb
attr_accessor :password_digest, :recovery_password_digest
Because the getter and setter methods created by attr_accessor
will override the methods that Ruby on Rails will create automatically for columns found in the database.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论