現在、検証は次のように設定されているため、ユーザーはパスワードを入力せずに一部の属性を編集できます。
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
しかし、何らかの理由で、これは同じことをしています。パスワードを変更せずに一部のユーザー属性を更新するにはどうすればよいですか?ありがとう!
昨日あなたに与えた解決策がこの問題につながるとは思いもしませんでした。ごめんなさい。
さて、インスピレーションを得て deviseから 、あなたは単にあなたのコントローラーをこのように更新するべきです:
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?
最後に、「password_changed?」かどうかを判断するために、encrypted_passwordが設定されているかどうかを確認するチェックを追加します。新しいレコードにパスワードを要求するため。
def password_changed?
!@new_password.blank? or encrypted_password.blank?
end
私はこれに苦労し、しばらくの間円を描いて回っていたので、ここにRails 4のソリューションを置くと思いました。
私がこれまでに見た答えはどれも私のユースケースを満たしていません。それらはすべて何らかの方法で検証をバイパスすることを含んでいるようですが、他のフィールドとパスワード(存在する場合)も検証できるようにしたいと思います。また、私は自分のプロジェクトでdeviseを使用していないので、それに特有のものを利用することはできません。
それは2つの部分の問題であることを指摘する価値があります:
ステップ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
私も同じ問題を抱えていましたが、上記の解決策はうまくいきませんでした。私の場合、本当の原因を見つけました。ユーザーモデルにencrypt_passwordコールバックがあり、毎回パスワードを空白に設定していました。
before_save:encrypt_password
このコールバックの最後に条件を追加して修正しました。
before_save:encrypt_password、:unless => Proc.new {| u | u.password.blank? }
2017年の回答:
Rails 5では、Michael Hartlの tutorial でも示されているように、モデルのこれらの線に沿って何かがあるだけで十分です。
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
allow_nil:trueは、ユーザーがパスワードの変更も必要とせずに自分の情報を編集できるようにするここでのキーです。
この時点で、これにより空のユーザーサインアップも可能になると考えるかもしれません。ただし、これは、パスワードの存在を自動的に検証するhas_secure_password
を使用することで防止されますが、create
メソッドのみが検証されます。
これは、説明を目的としたデモユーザーモデルです。
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-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 }, allow_nil: true
.
.
.
end
私はこれをデバイスで行う方法がわかりません。私の2セント。
正解はRails 4では機能しなくなりました。私の答えは最もクリーンで最も用途が広いはいつでも機能すると思いますany属性(パスワードだけでなく)を省略したい。このアプローチは、モデルの個別の属性をさまざまな場所で更新する場合に必要になります。
たとえば、Stack Overflowが行うことを実行し、パスワードをsecurity
ページで更新できるようにしたい場合、プロファイル画像はユーザー表示ビューで更新可能であり、ユーザーの情報の大部分はユーザー編集ビューで更新可能です。
1)hash class
をクラスメソッドで拡張して、空白の値を削除します。このメソッドを使用して、更新されていないがparamsハッシュにまだ存在している空白の値を削除します:
1a)lib
ディレクトリの下のext
ディレクトリに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初期化子で参照する:
config/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を実装します。更新していない属性をparamsハッシュから削除するクラスメソッド。次に、* update
メソッドではなく、update_attributes
メソッドを介してユーザーインスタンスを更新します!
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!
メソッドはparamsハッシュから属性を削除するため、たとえば、パスワードの検証は実行されません。 delete_blanks!
は、値がnilのハッシュエントリのみを削除し、空の文字列を持つものは削除しないことにも注意してください。したがって、誰かがユーザー作成フォーム(またはパスワードのフィールドを持つ任意のフォーム)でパスワードを省略した場合、ハッシュの:passwordエントリはnilにならず、空になるため、プレゼンス検証が有効になります。文字列:
3a)すべての検証でif:
オプションを使用します。
app/models/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は検証をスキップします。