2013-03-27 73 views
1

簡而言之:我有一個設計模型用戶我爲用戶添加一個選項,以便能夠在其個人檔案頁面中更改其密碼,而無需通過「忘記密碼」選項。總之,因爲這需要有領域的另一種形式::old_password, :new_password and :new_password_confirmation未原先模型,我不得不爲他們創造新的獨立驗證,Rails在提交空表單時不返回驗證錯誤

形式:

<%= 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 

型號:查看:驗證領域: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 

回答

1

基本上,你的密碼驗證不被達到。

使用change_password方法,您只是將值從控制器傳遞到該方法並使用它們來設置password。該模型沒有看到old_passwordnew_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 
+0

我之所以說是因爲如果我提交表單只有那些密碼字段我將獲得的用戶名,VCODE,apiid驗證錯誤.. – 2013-03-27 21:44:39

+0

看着深入到你的代碼,更新了我的答案。希望有所幫助。 – aguynamedloren 2013-03-27 21:54:19

+0

change_mathod不是它工作的問題。問題是與old_password/new_password等。我如何設置這些來驗證它們? – 2013-03-27 21:56:17