1

短い: 私はデバイスモデルのユーザーを持っています。ユーザーが「パスワードを忘れた」オプションを使用しなくても、プロファイルページでパスワードを変更できるようにするオプションを追加しています。とにかく、これにはフィールドを含む追加のフォームが必要だったので、:old_password, :new_password and :new_password_confirmationもともとモデルになかったので、それらに対して新しい個別の検証を作成する必要がありました。

フォーム:

<%= form_for(@user, :url => {:controller => :members, :action => :editpass}, :html => {:method => :post}) do |f| %>

    <input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>">
    <table class="tables no-border">
        <tr>
            <%= f.label :old_password, "Old password" %>
        </tr>
        <tr>
            <%= f.password_field :old_password, :autofocus => :true %>
        </tr>
        <tr>
            <%= f.label :new_password, "New password" %>
        </tr>
        <tr>
            <%= f.password_field :new_password %>
        </tr>
        <tr>
            <%= f.label :new_password_confirmation, "Repeat new password" %>
        </tr>
        <tr>
            <%= f.password_field :new_password_confirmation %>
        </tr>
        <tr>
            <input type="submit" value="Change" class="btn" />
        </tr>
    </table>
</form>

  <%= @user.errors.full_messages %>

<% end %>

コントローラー:

class MembersController < ApplicationController

  before_filter :authenticate_user!
  skip_before_filter :check_for_main

  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def editpass

    current_user.change_password(params[:old_password], params[:new_password])
    redirect_to member_path(current_user.id)

  end

  # User access restriction
  def ban
  end

  def unban
  end



end

モデル: LOOK AT: フィールドの検証:old_password / :new_password..

class User < ActiveRecord::Base

    # Virtual attributes
    # _password attributes serve in-profile password change and are not part of the model
    attr_accessor :login, :apiid, :vcode, :old_password, :new_password, :new_password_confirmation

    # Include default devise modules. Others available are:
    # :token_authenticatable, :confirmable,
    # :lockable, :timeoutable and :omniauthable
    devise  :database_authenticatable, :registerable, :confirmable,
            :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]

    # Registration show/edit form validation
    validates :username,    :presence   => true,
                            :length     => { :minimum => 6, :maximum => 255 },
                            :uniqueness => true

    validates :apiid,       :presence   => true,
                            :numericality => { :only_integer => true },
                            :acc_api    => true,
                            :on         => :create

    validates :vcode,       :presence   => true,
                            :length     => { :minimum => 20, :maximum => 255 },
                            :on         => :create

    # In profile password
    validates :old_password,    :presence   => true,
                                :length     => { :minimum => 8, :maximum => 255 },
                                :if         => :password_changed?

    validates :new_password,    :presence   => true,
                                :length     => { :minimum => 8, :maximum => 255 },
                                :if         => :password_changed?,
                                :confirmation   => true

    validates :new_password_confirmation,   
                                :presence   => true


    attr_accessible :login, :username, :group, :apiid, :vcode, :email, :password, :password_confirmation, :remember_me

    # Register character belonging to user
    after_create :register_characters

    # Model association
    has_many :apis
    has_many :characters

    # Allows user to reset password in profile
    # for Forgot Password look at Devise
    def change_password(oldpass, newpass)
        if self.valid_password?(oldpass)
            # User is logged out automatically by devise upon
            # password change
            self.password = newpass
            self.save
        else
            return false
        end
    end

    # Register account characters
    def register_characters
        require 'nokogiri'
        require 'open-uri'

        # Fetch account level xml
        uri = "https://api.eveonline.com/account/Characters.xml.aspx?keyID=#{self.apiid}&vCode=#{self.vcode}"
        xml = Nokogiri::XML(open(uri))
        row = xml.xpath("//row")

        # Create characters bound to user
        row.each do |entry|
            # Register new character
            character = Character.new(
                :charid     =>  entry['characterID'].to_i,
                :user_id    =>  self.id,
                :name       =>  entry['name'],
                :corp       =>  entry['corporationName']
                )
            character.save

            # Register character associated api credentials
            api = Api.new(
                :user_id        =>  self.id,
                :character_id   =>  character.id,
                :apiid          =>  self.apiid,
                :vcode          =>  self.vcode
                )
            api.save

            character.update_character
        end
    end

    # Check if user is banned before login
    def active_for_authentication?
      super && self.banned == false
    end

    # Redefine authentication procedure to allow login with username or email
    def self.find_for_database_authentication(warden_conditions)
      conditions = warden_conditions.dup
      if login = conditions.delete(:login).downcase
        where(conditions).where("username = '#{login}' OR email = '#{login}'").first
      else
        where(conditions).first
      end
    end

end
4

2 に答える 2

1

基本的に、パスワードの検証に達していません。

change_passwordメソッドを使用すると、コントローラーからそのメソッドに値を渡し、それらを使用してset password. モデルは設定されていないold_passwordためnew_password、検証できません。password_confirmationまた、モデルにパスワードを直接設定するだけで渡していないため( self.password = newpass)、password_confirmationも使用されていません。

別の回答で述べたようupdate_attributesに、Devise ドキュメントで推奨されているものを使用した方がよいでしょう。うまくいけば、私の説明が、あなたの方法が機能しない理由についての洞察を追加することを願っています。

メソッドに固執したい場合change_passwordは、値を属性に渡して、モデルによって検証されるようにする必要があります。次のようなことを試してください:

  #controller

  @user = current_user

  if @user.change_password(params[:old_password], params[:new_password], params[:new_password_confirmation])
    redirect_to member_path(current_user.id)
  else
    @errors = @user.errors.full_messages
    render 'edit_password_view' # not sure what this action is named
    # you now have an array of errors (@errors) that you can render however you see fit in the view
  end


  #model
  def change_password(oldpass, newpass, newpass_conf)
     self.password = newpass
     self.old_password = oldpass
     self.new_password = newpass
     self.new_password_confirmation = newpass_conf
     return self.save
  end
于 2013-03-27T21:43:22.617 に答える
0

パスワードの変更を使用する代わりに、ユーザー属性を更新するのが正しい方法だと思います。たぶん、このガイドが役に立ちます:

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password

于 2013-03-27T21:40:51.910 に答える