1

認証にdeviseを使用しています.deviseをセットアップした後、usersテーブルに他のフィールドをいくつか追加しました。ユーザーは電子メールとパスワードを入力するだけでサインアップでき、サインアップ後、ユーザーは自分のプロファイルを編集できます。そのために、:on => update を使用しました。しかし、パスワードの検証をリセットしようとすると、name cannot be blank や blah blah などのエラーが発生します。私はデバイスを使用しており、パスワードをリセットするために registrations#edit を使用しています。以下は私のユーザーモデルです。

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :dob, :phone, :address, :state, :city, :country, :photo

  has_attached_file :photo, :styles => { :small => "150x150>", :medium => "300x300>", :large => "500x500>" }
  has_many :blogs, :dependent => :destroy
  has_many :comments, :dependent => :destroy
  has_many :followers, :through => :blogs
  has_many :followings, :class_name => 'Follower', :foreign_key => 'user_id'
  has_many :following_blogs, :through => :followings, :source => :blog
  has_many :blog_followers, :through => :followers, :source => :user

  phone_regex = /^[0-9]+$/

  validates_attachment_size :photo, :less_than => 3.megabytes
  validates_attachment_content_type :photo, :content_type => ['image/jpeg','image/png','image/jpg','image/gif']

  validates :name, :presence => true, :on => :update
  validates :dob, :presence => true, :on => :update
  validates :phone, :format => { :with => phone_regex }, :length => { :is => 10 }, :on => :update
  validates :address, :presence => true, :on => :update
  validates :state, :presence => true,:length => { :maximum => 30 }, :on => :update
  validates :city, :presence => true, :length => { :maximum => 30 }, :on => :update
  validates :country, :presence => true, :length => { :maximum => 30 }, :on => :update
end
4

4 に答える 4

1

同じ問題がありました。これが私が見つけた解決策です。

デバイスの内部を少し掘り下げているので、これをテストすることをお勧めします。これを実装しようとしているときに、多くのものを壊したことがわかりました (一致するパスワードの確認を必要としない、またはパスワードを変更するなど!)

パスワードのリセットをチェックするテストスイートのスニペットを示す要点は次のとおりです

問題は、devise が検証を使用してパスワードが一致すること、有効なパスワードであること (つまり、短すぎないこと)、およびパスワード トークンが有効であることを確認することです。これは、valid? の使用をやめると、代わりに、特定のエラー メッセージを探す必要があります。

まず、ユーザー モデルで reset_password メソッドをオーバーライドする必要があります。この新しいメソッドは、エラー メッセージに「password」エラーが含まれていない場合、暗号化されたパスワード (password= メソッドの一部として作成される) を直接書き込みます。

元のデバイスの実装は次の場所にあります: https://github.com/plataformatec/devise/blob/18a8260535e5469d05ace375b3db3bcace6755c1/lib/devise/models/recoverable.rb#L39 (注意: after_password_reset は非推奨なので実装していません)

  def reset_password(new_password, new_password_confirmation)
    self.password = new_password
    self.password_confirmation = new_password_confirmation

    if valid?
      save
    elsif errors.messages.select { |k,v| k[/password/] }.empty?
      # No password errors, so we write the password directly to the DB
      update_attribute(:encrypted_password, encrypted_password)
      true
    else
      false
    end
  end

次に、更新メソッドがエラーが空かどうかも確認するため、独自の PasswordsController を実装する必要があります。パスワードエラーのみを探すように変更します。これが私のものです。

また、無効なモデルでパスワードをリセットしたときにリダイレクトが機能するように、respond_with を redirect_to に変更する必要がありました。なぜこれが必要だったのか、私にはよくわかりません。

#
# This is identical to the original devise password controller except
# that it allows resetting of passwords in invalid models (i.e.
# confirmed users without a valid profile
#

class Users::PasswordsController < Devise::PasswordsController
  # GET /resource/password/new
  # def new
  #   super
  # end

  # POST /resource/password
  # def create
  #   super
  # end

  # GET /resource/password/edit?reset_password_token=abcdef
  # def edit
  #   super
  # end

  # PUT /resource/password
  def update
    self.resource = resource_class.reset_password_by_token(resource_params)
    yield resource if block_given?

    # Was:
    #   if resource.errors.empty?
    # It's been changed to allow resetting passwords of invalid models
    if resource.errors.messages.select { |k,v| k[/password/] }.empty?
      resource.unlock_access! if unlockable?(resource)
      if Devise.sign_in_after_reset_password
        flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
        set_flash_message(:notice, flash_message) if is_flashing_format?
        sign_in(resource_name, resource)
        # Was:
        #   respond_with resource, location: after_resetting_password_path_for(resource)
        # but this didn't seem to redirect User's with invalid attributes so I've changed
        # it to a redirect
        redirect_to after_resetting_password_path_for(resource)
      else
        set_flash_message(:notice, :updated_not_active) if is_flashing_format?
        respond_with resource, location: new_session_path(resource_name)
      end
    else
      respond_with resource
    end
  end

  # protected

  # def after_resetting_password_path_for(resource)
  #   super(resource)
  # end

  # The path used after sending reset password instructions
  # def after_sending_reset_password_instructions_path_for(resource_name)
  #   super(resource_name)
  # end
end
于 2015-11-19T15:05:37.093 に答える
0

これに対する簡単な答えがあるかどうかはわかりません。サインアップ直後にユーザーにこれらのフィールドを更新するよう強制するのは良い考えだと思います (アカウントの「アクティベーション」など)。技術的には、これらの検証を定義した場合、ユーザーは実際には無効です。

それでも、次の回避策で検証を回避できると思います: 検証に:unlessオプション (これを参照) を追加します。

validates :name, :presence => true, :on => :update, :unless => :resetting_password?

次に、メソッドを定義し、resetting_password?そうしているときに true を返すようにします。これは、devise の登録コントローラーで変数を設定することで実行できます。attr_accessorこれを使えば十分だと思います。

もっと良い解決策があるかもしれませんが、それが今私が考えることができるものです。

于 2013-09-17T12:30:27.163 に答える
0

実際、問題は検証可能なデバイスモジュールを使用していることです。更新時でも、電子メールとパスワードの自動検証を行います。より良いオプションは、作成時に電子メールとパスワードに独自の検証を追加し、モデルでこれらの変更を行うか、完全に削除することです。

User Model

def email_required?
  false
end

def password_changed?
  false
end

それが役立つことを願っています。

于 2013-09-17T12:29:02.920 に答える