Why is setting password_digest working in my Rails console but not via controller logic?

huangapple go评论65阅读模式
英文:

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 ran bundle install
  • If I go into irb, I'm able to generate a new instance fine like so and see the password_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 &lt; 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 &lt; 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 ran bundle install
  • If I go into irb, I'm able to generate a new instance fine like so and see the password_digest:
3.2.1 :137 &gt; new_user = User.new(first_name: &quot;test&quot;, last_name: &quot;tester&quot;, email: &quot;foo@bar.com&quot;, password: &quot;123123123&quot;)
 =&gt; #&lt;User:0x0000000107c5bf40 id: nil, first_name: &quot;test&quot;, last_name: &quot;tester&quot;, email: &quot;foo@bar.com&quot;, password: nil, created_at: nil, updated_at: nil&gt;
3.2.1 :138 &gt; new_user.save
  TRANSACTION (0.7ms)  BEGIN
  User Exists? (0.8ms)  SELECT 1 AS one FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;email&quot; = $1 LIMIT $2  [[&quot;email&quot;, &quot;foo@bar.com&quot;], [&quot;LIMIT&quot;, 1]]
  User Create (0.5ms)  INSERT INTO &quot;users&quot; (&quot;first_name&quot;, &quot;last_name&quot;, &quot;email&quot;, &quot;password&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, $3, $4, $5, $6) RETURNING &quot;id&quot;  [[&quot;first_name&quot;, &quot;test&quot;], [&quot;last_name&quot;, &quot;tester&quot;], [&quot;email&quot;, &quot;foo@bar.com&quot;], [&quot;password&quot;, &quot;[FILTERED]&quot;], [&quot;created_at&quot;, &quot;2023-03-07 03:36:07.501992&quot;], [&quot;updated_at&quot;, &quot;2023-03-07 03:36:07.501992&quot;]]
  TRANSACTION (1.3ms)  COMMIT
 =&gt; true
3.2.1 :139 &gt; new_user.password_digest
 =&gt; &quot;$2a$12$aIcAuAdSnJhrLw0bWHTh1OgTTmUioB2ra3h12cFNs/IwnJdyRYJEW&quot;
# 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 &gt; latest_user = User.last
  User Load (1.1ms)  SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; DESC LIMIT $1  [[&quot;LIMIT&quot;, 1]]
 =&gt; #&lt;User:0x0000000107d75ca0 id: 27, first_name: &quot;Allday&quot;, last_name: &quot;Everyday&quot;, email: &quot;allday@everyday.com&quot;, 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&gt;
3.2.1 :141 &gt; latest_user.password_digest
 =&gt; 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 &lt; 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 &lt; ApplicationController
  # post &#39;/user/register&#39;
  def create
    user = User.new(user_params)
    begin
      user.save!
      session[:user_id] = user.id
      return render json: {success: true, status: 200}
    rescue =&gt; 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.

huangapple
  • 本文由 发表于 2023年3月7日 11:48:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75657885.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定