现在,用户可以编辑他们的一些属性而不必输入他们的密码,因为我的验证是这样设置的:
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }
然而,在用户这样做之后,他们的密码被删除- update_attributes将他们的密码更新为"。下面是我的更新定义:
def update
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
我也尝试过使用不同的定义,使用update_attribute代替:
def save_ff
@user = User.find(params[:id])
@user.update_attribute(:course1, params[:user][:course1] )
@user.update_attribute(:course2, params[:user][:course2] )
@user.update_attribute(:course3, params[:user][:course3] )
@user.update_attribute(:course4, params[:user][:course4] )
redirect_to @user
end
但出于某种原因,这是做同样的事情。如何在不更改密码的情况下更新某些用户属性?谢谢!
那么,从设计中获得灵感,你应该这样简单地更新你的控制器:
def update
params[:user].delete(:password) if params[:user][:password].blank?
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
这篇博客文章演示了您想要做的主要内容。
没有显示,但可能有帮助的是,向模型添加访问器:
attr_accessor :new_password, :new_password_confirmation
attr_accessible :email, :new_password, :new_password_confirmation
,并在用户提供新密码的条件下提供所有所需的验证。
validates :new_password, :presence => true,
:length => { :within => 6..40 },
:confirmation => true,
:if => :password_changed?
最后,我将添加一个检查来查看encrypted_password是否已设置,以便确定"password_changed?"是否需要在新记录上输入密码。
def password_changed?
!@new_password.blank? or encrypted_password.blank?
end
我一直在努力解决这个问题,在圈子里转了一段时间,所以我想我把我的Rails 4解决方案放在这里。
到目前为止,我所看到的答案都不符合我的用例,它们似乎都以某种方式绕过验证,但我希望能够验证其他字段和密码(如果存在)。我也没有在我的项目中使用设计,所以我不能使用任何特别的东西。
值得指出的是,这是一个两部分的问题:
步骤1 -如果密码为空,则需要从强参数中删除密码和确认字段,就像在控制器中一样:
if myparams[:password].blank?
myparams.delete(:password)
myparams.delete(:password_confirmation)
end
步骤2 -您需要更改验证,以便在未输入密码时不验证密码。我们不希望它被设置为空白,因此我们之前从参数中删除了它。
在我的例子中,这意味着在我的模型中有这个作为验证:
validates :password, :presence => true, :confirmation => true, length: {minimum: 7}, :if => :password
注意:if =>:password -跳过检查是否没有设置密码。
# It smells
def update
if params[:user][:password].blank?
params[:user].delete :password
params[:user].delete :password_confirmation
end
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
# Refactoring
class User < ActiveRecord::Base
...
def update_attributes(params)
if params[:password].blank?
params.delete :password
params.delete :password_confirmation
super params
end
end
...
end
def update
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
# And little better
class User < ActiveRecord::Base
...
def custom_update_attributes(params)
if params[:password].blank?
params.delete :password
params.delete :password_confirmation
update_attributes params
end
end
...
end
def update
if @user.custom_update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
2017答:
在Rails 5中,正如Michael Hartl的教程所指出的,在你的模型中沿着这些行得到一些东西就足够了:
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
allow_nil: true是这里的关键。这允许用户编辑他/她的信息,而不需要修改密码。
在这一点上,人们可能会认为这也将允许空用户注册;然而,这可以通过使用has_secure_password
来防止,CC_1会在create
方法中自动验证密码是否存在。
这是一个用于说明目的的演示User
模型:
class User < ApplicationRecord
attr_accessor :remember_token
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-.]+.[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 }, allow_nil: true
end
不幸的是,我不知道如何使这个工作在设计。🖖欢呼声。
我有同样的问题,上面的解决方案对我不起作用。我发现了真正的罪魁祸首:我在我的User模型中有一个encrypt_password回调,它每次都将密码设置为空白。
before_save: encrypt_password
我通过在这个回调的末尾添加一个条件来修复它:
before_save:encrypt_password,:unless => Proc.new {|u| u.password.blank?}
正确答案不再适用于rails 4。我相信我的答案是最干净和最通用的,它将在您想要省略任何属性(不仅仅是密码)时工作。如果您想要在许多不同的地方更新任何模型的单独属性,则需要这种方法。
例如,如果您想做Stack Overflow所做的事情,并通过security
页面更新密码,通过用户显示视图更新配置文件图像,并通过用户编辑视图更新用户的大部分信息。
1)用一个类方法扩展hash class
来删除空白值。我们将使用此方法删除未更新但仍存在于参数散列中的空白值:
1a)在lib
目录下创建一个hash.rb
文件:
$ mkdir lib/ext
$ touch lib/ext/hash.rb
1b)在hash.rb
内部,'创建'一个Hash
类并创建一个.delete_blanks!
方法:
/lib/ext hash.rb
class Hash
def delete_blanks!
delete_if { |k, v| v.nil? }
end
end
1c)要求这个文件(和你的整个lib目录)到rails中在初始化器中引用它:
配置/boot.rb
# other things such as gemfiles are required here, left out for brevity
Dir['lib/**/*.rb'].each { |f| load(f) } # requires all .rb files in the lib directory
2)在users#update操作中,实现我们闪亮的新delete_blanks!类方法从参数哈希中删除我们不更新的属性。然后,通过update_attributes
方法更新用户实例,而不是update
方法!
2a)首先,让我们使用delete_blanks!方法修复user_params散列:
app/controllers/users_controller.rb
new_params = user_params.delete_blanks!
2b)现在让我们使用update_attributes
方法更新实例,(同样,不是update
方法):
app/controllers/users_controller.rb
@user.update_attributes(new_params)
完成的users#update
动作应该是这样的:
app/controllers/users_controller.rb
def update
new_params = user_params.delete_blanks!
if @user.update_attributes(new_params)
redirect_to @user, notice: 'User was successfully updated.'
else
render action: 'edit' // or whatever you want to do
end
end
3)在User
模型中,将if: :<attribute>
选项添加到所有验证中。这是为了确保只有当属性出现在params散列中时才触发验证。我们的delete_blanks!
方法将从参数散列中删除该属性,因此不会运行例如密码的验证。同样值得注意的是,delete_blanks!
只删除值为nil的哈希条目,而不删除包含空字符串的哈希条目。因此,如果有人在用户创建表单(或任何有密码字段的表单)上遗漏了密码,则存在验证将生效,因为散列的:password条目不会为nil,它将是一个空字符串:
3a)在所有验证中使用if:
选项:
应用程序/模型/user.rb
VALID_EMAIL_REGEX = /[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]/
validates :first_name, presence: true, if: :first_name
validates :last_name, presence: true, if: :last_name
validates :user_name, presence: true, if: :user_name
validates :email, presence: true,
uniqueness: { case_sensitive: false },
format: { with: VALID_EMAIL_REGEX }, if: :email
validates :password, length: { minimum: 6, maximum: 10 }, if: :password
就是这样。现在,用户模型可以在应用程序的许多不同的表单上更新。属性的存在验证仍然会在包含它的字段的任何表单上发挥作用,例如,密码存在验证仍然会在user#create
视图中发挥作用。
这可能看起来比其他答案更冗长,但我相信这是最健壮的方法。您可以在无限数量的不同模型上单独更新User
实例的无限数量的属性。只要记住,当您想要对新模型执行此操作时,您需要重复步骤2a), 2b)和3a)
@user.username=params[:username]
if @user.update_attribute(:email,params[:email])
flash[:notice]="successful"
else
flash[:notice]="fail"
end
以上代码可以更新用户名和电子邮件字段。因为update_attribute可以更新脏字段。但遗憾的是,update_attribute会跳过验证。
我也有同样的问题。我无法用
修复它params[:user].delete(:password) if params[:user][:password].blank?
我只能通过对每个项目单独执行"update_attribute"来使其工作,例如
if ( @user.update_attribute(:name, params[:user][:name]) &&
@user.update_attribute(:email, params[:user][:email]) &&
@user.update_attribute(:avatar, params[:user][:avatar]) &&
@user.update_attribute(:age, params[:user][:age]) &&
@user.update_attribute(:location, params[:user][:location]) &&
@user.update_attribute(:gender, params[:user][:gender]) &&
@user.update_attribute(:blurb, params[:user][:blurb]) )
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user info"
render 'edit'
end
这显然是一个完全的黑客,但这是唯一的方法,我可以弄清楚它没有搞乱验证和删除密码!