【问题标题】:Updating a User model resets password? Rails question更新用户模型会重置密码?导轨问题
【发布时间】:2011-08-25 13:18:13
【问题描述】:

在我的控制器中,我尝试更新用户实例的rank 属性(整数)。例如从 1 到 2。

我这样做是:

@user = User.find(params[:id])
@user.rank = 2
@user.save(:validate => false)

由于某种原因,正在保存的用户的密码被删除,这样他们就可以在没有密码的情况下登录我的网站。我尝试过使用和不使用:validate => false 参数。

有什么理由吗?帮助?非常感谢

型号代码

类用户

validates :login, :presence => true, :length => { :maximum => 15, :minimum => 4 }, :uniqueness => true
validates :fname, :presence => true, :length => {:minimum => 2 }
validates :lname, :presence => true, :length => {:minimum => 2 }
validates :email, :presence => true, :format => { :with => email_filter}, :uniqueness => { :case_sensitive => false }
validates :password,  :presence => true, :confirmation => true, :length => { :within =>4..40 }
validates :lane_id, :presence => true

before_save :encrypt_password
has_many :reports
has_many :accomplishments
belongs_to :lane 


def has_password?(submitted_password)
  encrypted_password == encrypt(submitted_password)
end

def self.authenticate(login, submitted_password)
  user = find_by_login(login)
  return nil  if user.nil?
  return user if user.has_password?(submitted_password)
end

def self.authenticate_with_salt(id, cookie_salt)
  user = find_by_id(id)
  (user && user.salt == cookie_salt) ? user : nil
end

def current_report
  report = (Report.order("created_at DESC")).find_by_user_id(@user.id)
end

private

def encrypt_password
  self.salt = make_salt if new_record?
  self.encrypted_password = encrypt(password)
end

def encrypt(string)
  secure_hash("#{salt}--#{string}")
end

def make_salt
  secure_hash("#{Time.now.utc}--#{password}")
end

def secure_hash(string)
  Digest::SHA2.hexdigest(string)
end

结束

【问题讨论】:

  • 你有前置过滤器还是后置过滤器?
  • 不,只是默认的标准导轨形式
  • 嗯,我有一个 before_save :encrypt_password。会这样做吗?我打电话 :validate => false 虽然...
  • 发布您的用户模型的代码
  • 好吧,我猜是因为我正在保存用户,并且有一个 before_save 过滤器来加密“不存在”的密码,所以它会变成空白?

标签: ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

如果存在密码,您只想加密密码,因此在回调中添加条件

before_save :encrypt_password, :unless => "password.blank?"

此外,您不希望每次更新用户记录时都验证密码。您可以删除:presence => true 验证,并添加一个条件以仅在密码存在时运行其他验证。

validates :password,  :confirmation => true, :length => { :within =>4..40 }, :unless => "password.blank?"

【讨论】:

  • 由于某种原因,这在 Rails 3.2.2 中并不适用。密码不再是空字符串。每次我用这个代码更改用户对象时,加密的密码字符串都是不同的,如果密码为空,它应该是相同的。
  • password 是模型上的虚拟属性(这是典型的实现)吗?如果是这样,您必须在代码中的某处设置密码。如果不是,则需要进行比 cmets 更长时间的讨论。
  • 不,这是真正的数据库字段。但我还是不明白。当 Rails 在 DB 上执行 UPDATE 时,它只更新查询中的字段,而不更新密码。我正在从 PHP 切换,我主要从 PHP 类执行直接查询,所以我仍然不习惯 ORM
  • 首先,听起来您将用户的未加密密码保存在password 字段中,并将他们的加密密码保存在encrypted_password 字段中。保存未加密的密码会破坏加密的目的,并且在您的情况下,它还会在每次保存时触发加密过程,因为密码不是空白的。看看这个在 Rails asciicasts.com/episodes/250-authentication-from-scratch 中创建身份验证的秘诀。
  • 此外,还有几个不错的插件可以为您的应用添加身份验证。看看现在最流行的 Devise。
【解决方案2】:

您有一个before_filter,它会在您每次保存模型时对密码进行加密。而不是 before_filter 使用这样的东西:

def password=(new_password)
  self.salt = make_salt if new_record?
  self.encrypted_password = encrypt(new_password)
end

【讨论】:

  • 那么不要使用 before_save :encrypt_password" 吗?
  • 没错。每次保存模型时都会调用before_save,并且只有在更新密码时才会调用此代码。
  • 如果我去掉 before_save 调用,那么整个加密过程永远不会发生,因为“encrpyt_password”只在顶部调用一次..所以我还是有点困惑..跨度>
  • 每次设置密码时,password= 都会被调用,如果您查看我的代码,就会发现您获得了加密密码。
  • 所以我完全去掉了 'before_save :encrypt_password' 行,并将 'encrpyt_password' 函数重命名为 'password=(new_password)' 但是当我尝试更新时,没有任何变化。我做的改变对吗?
【解决方案3】:

我知道这已经很晚了,但实际上我只是偶然发现了这篇写于 2009 年的 therailsways.com 上的文章,但仍然对我有用,以防其他通过 Google 来到这里的人可能遇到同样的问题。

before_save :encrypt_password, :if => :password_changed?

我遇到了同样的问题,我的密码会在更新时重新加密,但我只想在创建用户时对其进行加密。

我一直在寻找 before_save 的替代品,但它们都没有真正做到这一点。然而,这确实做到了,我所要做的就是添加 if 条件。效果很好。

【讨论】:

    猜你喜欢
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 2019-04-03
    相关资源
    最近更新 更多