29

現在、検証は次のように設定されているため、ユーザーはパスワードを入力せずに一部の属性を編集できます。

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 

しかし、何らかの理由でこれは同じことをしています。パスワードを変更せずに一部のユーザー属性を更新するにはどうすればよいですか?ありがとう!

4

9 に答える 9

25

昨日あなたに与えた解決策がこの問題につながるとは思いもしませんでした。ごめん。

さて、デバイスからインスピレーションを得て、あなたは単にあなたのコントローラーをこのように更新するべきです:

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
于 2011-08-17T12:23:05.697 に答える
12

このブログ投稿は、あなたがやりたいことの原則を示しています。

表示されていませんが、役立つ場合がありますが、モデルにアクセサーを追加することです。

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_pa​​sswordが設定されているかどうかを確認するチェックを追加します。新しいレコードにパスワードを要求するため。

  def password_changed?
    !@new_password.blank? or encrypted_password.blank?
  end
于 2012-03-18T20:45:49.283 に答える
11

私はこれに苦労し、しばらくの間円を描いて回っていたので、Rails4ソリューションをここに置くと思いました。

私がこれまでに見た答えはどれも私のユースケースを満たしていません。それらはすべて何らかの方法で検証をバイパスすることを含んでいるようですが、他のフィールドとパスワード(存在する場合)も検証できるようにしたいと思います。また、私は自分のプロジェクトで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に注意してください-パスワードが設定されていないかどうかのチェックをスキップします。

于 2013-11-22T11:59:36.753 に答える
6
# 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
于 2012-06-26T21:11:00.317 に答える
4

私も同じ問題を抱えていましたが、上記の解決策はうまくいきませんでした。私の場合、本当の原因を見つけました。ユーザーモデルにencrypt_passwordコールバックがあり、毎回パスワードを空白に設定していました。

before_save:encrypt_password

このコールバックの最後に条件を追加して修正しました。

before_save:encrypt_password、:unless => Proc.new {| u | u.password.blank?}

于 2012-01-09T15:35:14.577 に答える
4

2017年の回答:

MichaelHartlのチュートリアルでも示されているRails5では、モデルのこれらの線に沿って何かがあれば十分です。

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

deviseでこれを行う方法がわかりません。私の2セント。

于 2017-07-26T13:59:49.937 に答える
3

正解はもはやレール4では機能しません。私の答えは、(パスワードだけでなく)属性 を省略したいときにいつでも機能する最もクリーンで用途の広いものだと思います。このアプローチは、さまざまな場所でモデルの個別の属性を更新する場合に必要になります。

たとえば、Stack Overflowが行うことを実行し、securityページを介してパスワードを更新可能にしたい場合、ユーザー表示ビューを介して更新可能なプロファイルイメージと、ユーザー編集ビューを介して更新可能なユーザー情報の大部分を使用します。

1)クラスメソッドでを拡張しhash classて、空白の値を削除します。このメソッドを使用して、更新されていないがparamsハッシュにまだ存在している空白の値を削除します。

1a)ディレクトリ内のディレクトリの下にhash.rbファイルを作成します。libext

コマンドライン

$ 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ディレクトリ全体)を、初期化子でそれを参照するレールに要求します。

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_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ハッシュに存在する場合にのみ検証がトリガーされるようにするためです。このメソッドはparamsdelete_blanks!ハッシュから属性を削除するため、たとえば、パスワードの検証は実行されません。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)を繰り返す必要があることを覚えておいてください。

于 2014-04-06T20:58:07.957 に答える
0
@user.username=params[:username]
if @user.update_attribute(:email,params[:email])

  flash[:notice]="successful"
else
  flash[:notice]="fail"
end

上記のコードは、ユーザー名とメールフィールドを更新できます。update_attributeはダーティフィールドを更新できるためです。しかし、それは残念です。update_attributeは検証をスキップします。

于 2012-11-13T03:38:40.700 に答える
-1

私も同じ問題を抱えていました。私はそれを修正することができませんでした

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

これは明らかに完全なハックですが、検証をいじったりパスワードを削除したりせずにそれを理解できる唯一の方法です!

于 2011-08-17T16:59:00.270 に答える