2010-07-17 49 views
7

所以我有一個用戶模型,包括登錄名,電子郵件地址,密碼,密碼確認,名稱,頭像(圖片)等。前5個驗證,基本上說明所有5個都需要存在才能創建一個新模型。Rails - update_attributes來驗證

但是,這對我來說更新有關問題。

我有一個編輯頁面,用戶只能編輯他們的名字和頭像。我目前不打算讓他們更改他們的登錄名,我希望從其他頁面更改電子郵件和密碼。

所以編輯形式如下:

<% form_for @user, :html => { :multipart => true } do |u| %> 
<p> 
    <label>Name:</label> 
    <%= u.text_field :name %> 
</p> 
<p> 
    <label>Avatar:</label> 
    <%= display_user_avatar %> 
    <%= u.file_field :avatar%> 
</p> 
<p> 
    <%= submit_tag %> 
</p> 
<% end %> 

如果我試圖做一個@user.update_attributes(params[:user]),則因爲只有2個PARAMS是nameavatar,更新失敗,因爲東西像密碼,確認密碼,電子郵件等是必需的,以驗證條目,他們根本不存在這種形式。

我可以通過做@user.update_attribute(:name, params[:user][:name])來解決這個問題,但是我擔心避免驗證是否是一件好事?尤其是關於密碼更新等問題,我需要驗證新密碼。

還有別的辦法嗎?

如果我做到這一點簡單地使用update_attribute爲:name:avatar,我怎麼會去這樣做呢?

會這樣嗎?

params[:user].each do |attribute| 
    @user.update_attribute(attribute, params[:user][attribute]) 
end 

這是一個可接受的方式來做到這一點...?


--edit作爲跟進 -
Okie,我想如你所說,做

所以它做的!版本,異常夾在瀏覽器中顯示&是:

Validation failed: Password is too short (minimum is 5 characters) 

服務器日誌中的信息是:

Processing UsersController#update (for 127.0.0.1 at 2010-07-18 11:56:59) [PUT] 
    Parameters: {"user"=>{"name"=>"testeeeeee"}, "commit"=>"Save changes", "action"=>"update", "_method"=>"put", "authenticity_token"=>"BMEGRW/pmIJVs1zlVH2TtZX2TQW8soeCXmMx4kquzMA=", "id"=>"tester", "controller"=>"users"} 

Urm。看着這個,我剛剛意識到它正在提交"id"=>"tester"。現在,我設置了路由,以便顯示用戶登錄名,而不是user_id ...可能是爲什麼?它試圖找到user_id == tester用戶的更新,但由於它不存在,它會嘗試創建一個? 實際上是由於路線我做錯了嗎?

嗯......耙路線告訴我的路線是:

edit_user GET /users/:id/edit(.:format)        {:action=>"edit", :controller=>"users"} 
      PUT /users/:id(.:format)         {:action=>"update", :controller=>"users"} 

我設置了這樣的路線在user.rb文件:

def to_param 
    "#{login}" 
    end 

,但它肯定被顯示的login代替id這麼長的時間。但是在更新操作開始時我也正確地做了一個@user = User.find_by_login(params[:id]),然後更新@user

我很困惑。 >。 <


二更新:

User.rb驗證的東西如下:

validates_length_of :login, :within => 3..20 
    validates_length_of :password, :within => 5..20 
    validates_presence_of :login, :email, :password, :password_confirmation, :salt, :name, :on => :create 
    validates_uniqueness_of :login, :case_sensitive => false 
    validates_confirmation_of :password 
    validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message => "format is invalid." 
    attr_accessor :password, :password_confirmation 

而且hashed_pa​​ssword部分是在這裏:

def password=(pass) 
    @password = pass 
    self.salt = User.random_string(10) if !self.salt? 
    self.hashed_password = User.encrypt(@password, self.salt) 
    end 

u.attributes給我

>> u.attributes 
=> {"salt"=>"NHpH5glxsU", "name"=>"test er", "avatar_updated_at"=>nil, "updated_at"=>Sat Jul 17 07:04:24 UTC 2010, "avatar_file_size"=>nil, "avatar_file_name"=>nil, "hashed_password"=>"84f8675c1ed43ef7f8645a375ea9f867c9a25c83", "id"=>1, "avatar_content_type"=>nil, "login"=>"tester", "email"=>"[email protected]", "created_at"=>Fri May 07 10:09:37 UTC 2010} 

Urmmm ......好了,這是你說的,關於虛擬屬性password是不存在的實際... 那麼,如何避開? Bugger,在這裏我認爲我正在用我自己的驗證代碼擺弄...

更改爲其中一個身份驗證插件有多簡單?我需要創建一個新的用戶模型嗎?還是應該插件能夠使用我現有的插件?

感謝所有幫助到目前爲止,btw! :D

+0

PS:是的,'

+0

你描述的內容對我來說聽起來不太合適,我敢肯定,如果你使用'Hash'做'update_attributes'只包含一部分屬性,那麼所有其他的屬性都保留下來他們之前的值意味着驗證不應該失敗 – mikej 2010-07-17 15:53:48

回答

10

我已經檢查了這一點,並通過update_attributes工作正常只是2屬性的部分更新。所有其他屬性都保留有以前的值,這意味着驗證不應該失敗。有幾件事可以嘗試:

  • 在您的控制器操作中,您是否通過User.find加載用戶?即你是從一個有效的模型開始的。
  • 您確定由於驗證錯誤而導致更新失敗嗎?嘗試用update_attributes!替換update_attributes。如果更新由於驗證而失敗,後者將拋出異常。或在嘗試更新後檢查@user.errors以確認哪個驗證失敗。

更新

如果User.find_by_login沒有找到匹配的記錄,將返回nil並不會爲你創建一個新的記錄。數據庫中的測試人員用戶有可能是否有太短的密碼?也許該用戶是在將驗證放入代碼之前創建的?在保存記錄之前,您是否使用任何類型的插件或回調來加密用戶密碼?password實際上是一個未保存的虛擬屬性,而實際的密碼位於encrypted_password之類的字段中?

script/console試試這個(使用你正在測試與應用程序相同的環境 - 開發或生產)

> user = User.find_by_login 'tester' 
> user.valid? 
> user.attributes 

user.valid?將返回falsetrue並會告訴你用戶是否有效啓動與之前,你甚至嘗試更新。

更新2(固定驗證)

在修復自己的代碼方面,你可以添加一個方法類似下面你User型號:

def password_validation_required? 
    hashed_password.blank? || [email protected]? 
end 

,然後更新所有與密碼相關的驗證規則,以便它們僅適用於此方法返回true例如

validates_length_of :password, :within => 5..20, 
    :if => :password_validation_required? 

這是什麼要說的是隻能做密碼驗證規則,如果我們還沒有一個hashed_password(上例如新用戶),或是否有新的明文密碼已經通過password=規定。如果用戶已經有密碼並且保持不變,則跳過密碼驗證。

雖然你是正確的考慮使用插件。編寫自己的身份驗證代碼可能是一項有趣的練習,如果您有一些不尋常的要求,則可能需要這樣做。不好的一面是可能存在你沒有想到的安全問題。改裝類似restful_authentication到你的應用程序不應該太糟糕。您可能只需要重命名User型號的一個或兩個字段。

+0

Okie,我剛剛更新了原來的帖子和我嘗試過的結果,哦,當我剛做'update_attributes'時,閃爍顯示'@users。錯誤',我在閃存中有一個'#',就是這樣,這讓我想知道它是否是'id = tester'更新的問題... – 2010-07-18 02:11:59

+0

@ Jty.tan答案更新了一些建議,讓我知道他們是否有任何幫助 – mikej 2010-07-18 09:32:43

+0

哦,你是對的...我做了一個'u.valid?',並得到了一個'虛假'的回報 嗯......我只是試着用最新的用戶我創建了(成功的),並且我還得到了'有效?'的虛假回報...... 因此,它與我的用戶模型和驗證有關?是的,我的用戶密碼是加密的,並且加密的密碼是保存的密碼... 我將再次用我的user.rb中的驗證更新。 – 2010-07-18 13:39:27