2011-03-24 76 views
8

這就是所有的彈珠,如果我可以解決這個問題,那麼我有一個項目完成。Ruby on Rails/Devise - 需要密碼更改電子郵件

無論如何,我正在使用Ruby on Rails 3與Devise進行用戶認證。您可能知道,默認情況下,在用戶admin/edit中,如果用戶提供新密碼,則必須在current_password字段中輸入其當前密碼。有關於如何禁用current_password的信息TON,以便用戶可以自由更改和保存。

但是,在做相反的事情時我發現很少:需要更多字段的當前密碼......在我的情況下,電子郵件字段。並且只有當該電子郵件地址被更改時才需要當前密碼,而不是如果它保持不變。目前用戶可以自由更改他們的電子郵件,而不必提供他們當前的密碼,出於安全原因,我不想要這樣。

查看Devise wiki後,我確實發現了this page,我想我可以通過反轉此代碼來完成此解決方案。我設法工作,這有點出我user.rb模型(我去掉了不必要的邏輯爲這個職位)....

class User < ActiveRecord::Base 
    # Include default devise modules. Others available are: 
    # :token_authenticatable, :confirmable, :lockable and :timeoutable 
    devise :database_authenticatable, :registerable, :confirmable, 
     :recoverable, :rememberable, :trackable, :validatable 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :name, :email, :password, :password_confirmation, :avatar, :remember_me, :agree 
    attr_accessor :accessible, :agree, :signed_in 
    attr_readonly :name 

    # Validation 
    validates :name, :presence => TRUE, :uniqueness => TRUE, :length => { :within => 4..20 } 
    validates :agree, :term_agreement => TRUE, :unless => :signed_in 
    validates_attachment_size :avatar, :less_than => 1.megabyte 
    validates_attachment_content_type :avatar, :content_type => ['image/jpeg', 'image/png', 'image/gif'] 
    validates :current_password, :presence => TRUE, :if => :password_required? 

    protected 

    def password_required? 
    email_changed? 
    end 

end 

這「差不多」的作品。如果我保存用戶配置文件而不更改任何內容,或者更改其他非密碼必填字段(如用戶頭像),則配置文件可以很好保存,無需密碼。到現在爲止還挺好。

如果我更改電子郵件地址,驗證觸發....但是會發生什麼是根據需要觸發current_password和密碼(對於新密碼)字段。如果我在所有三個密碼(password,password_confirmation,current_password)中填入密碼,它就不會使用,只是再次發出驗證錯誤。

基本上,只有當電子郵件地址被更改時,才需要current_password。我將如何在我的代碼中完成這項工作?

  • UPDATE *******

我通過bowsersenior檢查了我的日誌響應下面的建議,並請參閱下面的行,當我試圖保存和更新電子郵件..

User Load (0.2ms) SELECT `users`.`id` FROM `users` WHERE (LOWER(`users`.`email`) = LOWER('[email protected]')) AND (`users`.id <> 1) LIMIT 1 
    User Load (0.2ms) SELECT `users`.`id` FROM `users` WHERE (`users`.`name` = BINARY 'Administrator') AND (`users`.id <> 1) LIMIT 1 
    SQL (0.1ms) ROLLBACK 

我不知道'ROLLBACK'與最終的問題有什麼關係嗎?

回答

4

試試這個:

validates :current_password, :presence => TRUE, :if => :email_changed? 

我強烈建議你獨自離開password_required?。這可能會導致安全性和不穩定行爲的錯誤。

+0

更接近,但並不完全在那裏。現在它只是在當前密碼字段上發出錯誤 - 如果沒有填寫 - 但奇怪的是,即使您填寫了正確的密碼,它也會吐出另一個「當前密碼不能爲空」的錯誤...這很奇怪。 – Shannon 2011-03-24 02:09:24

+0

我注意到我的日誌文件中有一些有趣的東西,我目前無法解釋,我將它貼在上面的原始文章後面。 – Shannon 2011-03-24 02:25:07

+0

我想我知道發生了什麼。您的模型不允許設置':current_password',因爲您正在使用'attr_accessible'防止大規模分配。嘗試將':current_password'添加到'attr_accessible'後面的字段列表中。無法告訴你我被這個問題困擾了多少次! – bowsersenior 2011-03-24 03:33:51

4

我相信這樣的設計方式如下:

class RegistrationsController < Devise::RegistrationsController 
    def update 
    @user = User.find(current_user.id) 

    successfully_updated = if needs_password?(@user, params) 
     @user.update_with_password(params[:user]) 
    else 
     # remove the virtual current_password attribute update_without_password 
     # doesn't know how to ignore it 
     params[:user].delete(:current_password) 
     @user.update_without_password(params[:user]) 
    end 

    if successfully_updated 
     set_flash_message :notice, :updated 
     redirect_to after_update_path_for(@user) 
    else 
     render "edit" 
    end 
    end 

    private 

    def needs_password?(user, params) 
    user.email != params[:user][:email] 
    end 
end 

換句話說,一切都發生在控制器級別,我們請使用User#update_with_password,當用戶想改變他的電子郵件(我們知道,通過在更新操作中調用needs_password?)或User#update_without_password,當用戶更改其他配置文件數據時。

還記得你需要在你的路線, 「註冊」 這一新RegistrationsController:

devise_for :users, :controllers => { :registrations => "registrations" } 

來源:

1

類似帕維爾的答案,而不是覆蓋控制器方法更新,這個怎麼樣,基於這個devise wiki

class RegistrationsController < Devise::RegistrationsController 
    protected 

    def update_resource(resource, params) 
    if resource.email != params[:email] || params[:password].present? 
     super 
    else 
     params.delete(:current_password) 
     resource.update_without_password(params) 
    end 
    end 
end