2011-08-23 74 views
5

我在我的用戶模型下驗證並更新單個屬性軌

attr_accessible :avatar, :email 

validates_presence_of :email 
has_attached_file :avatar # paperclip 

validates_attachment_size :avatar, 
          :less_than => 1.megabyte, 
          :message => 'Image cannot be larger than 1MB in size', 
          :if => Proc.new { |imports| !imports.avatar_file_name.blank? } 
在我的控制器之一

我只想更新和驗證化身場不更新和驗證電子郵件

我怎樣才能做到這一點?

例如(這是不行的)

if @user.update_attributes(params[:user]) 
# do something... 
end 

我也試圖與update_attribute('avatar', params[:user][:avatar]),但會跳過化身領域的驗證也是如此。

+1

複製? http://stackoverflow.com/questions/457239/is-there-a-way-to-validate-a-specific-attribute-on-an-activerecord-without-instan/457313#457313 –

+0

不,我想'模擬.valid?'驗證一切。我正在尋找只驗證一個屬性。 – Madhusudhan

回答

13

你可以validate the attribute by hand並使用update_attribute,即skips validation。如果您添加this to your User

def self.valid_attribute?(attr, value) 
    mock = self.new(attr => value) 
    if mock.valid? 
    true 
    else 
    !mock.errors.has_key?(attr) 
    end 
end 

然後正是如此更新的屬性:

if(!User.valid_attribute?('avatar', params[:user][:avatar]) 
    # Complain or whatever. 
end 
@user.update_attribute('avatar', params[:user][:avatar]) 

你應該讓你的單一屬性更新,而只有(手動)驗證該屬性。

如果您看看Milan Novota的valid_attribute?如何工作,您會看到它執行驗證,然後檢查以確定具體的attr是否有問題;因爲valid_attribute?只針對您感興趣的屬性的驗證失敗,所以其他驗證失敗並不重要。

如果您要做很​​多這些東西,那麼您可以給用戶添加一個方法:

def update_just_this_one(attr, value) 
    raise "Bad #{attr}" if(!User.valid_attribute?(attr, value)) 
    self.update_attribute(attr, value) 
end 

並用它來更新你的單一屬性。

+0

這也將檢查電子郵件驗證,只是不是頭像。 – Madhusudhan

+0

@Madhusudhan:您可以手動設置驗證並使用'update_attribute'。請參閱我的更新。 –

+0

有幫助!謝謝! – Madhusudhan

1

你有沒有試圖把一個條件對validates_presence_of :email

http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000083

配置選項:

如果 - 指定的方法,PROC或字符串來調用,以確定是否應當發生對所述驗證(例如:如果=>:allow_validation,或:若=> Proc.new {|用戶| user.signup_step> 2})。該方法,proc或字符串應返回或評估爲真或假的值。除非 - 指定要調用的方法,proc或字符串以確定驗證是否不應該發生(例如:除非=>:skip_validation或:除非=> Proc.new {| user | user.signup_step < = 2 })。該方法,proc或字符串應返回或評估爲真或假的值。

1

我假設你需要這個,因爲你有一個多步向導,你首先上傳頭像並在稍後填寫電子郵件。

據我所知,您的驗證,因爲他們,我看不出有什麼好工作的解決方案。要麼你驗證全部,要麼更新頭像而不驗證。如果它是一個簡單屬性,則可以檢查新值是否單獨通過驗證,然後更新模型而不驗證(例如使用update_attribute)。

我可以建議兩種可能的替代辦法:

  • 要麼你確保電子郵件始終是第一次進入,我相信這是個不錯的解決方案。然後,每次保存,驗證都會被滿足。
  • 否則,更改驗證。如果數據庫中有不符合驗證的記錄,爲什麼還要聲明對模型進行驗證?這是非常直觀的。

所以,我建議是這樣的:

validate :presence_of_email_after_upload_avatar 

def presence_of_email_after_upload_avatar 
    # write some test, when the email should be present 
    if avatar.present? 
    errors.add(:email, "Email is required") unless email.present? 
    end 
end 

希望這有助於。

+0

errors.add(:email,「需要電子郵件」)生成錯誤=「需要電子郵件電子郵件」。將「需要電子郵件」更改爲「必填」 –

6

的條件?

validates_presence_of :email, :if => :email_changed? 
1

這是我的解決方案。 它保持與.valid一樣的行爲?方法,女巫會返回true或false,並在模型被調用時添加錯誤。

class MyModel < ActiveRecord::Base 
    def valid_attributes?(attributes) 
    mock = self.class.new(self.attributes) 
    mock.valid? 
    mock.errors.to_hash.select { |attribute| attributes.include? attribute }.each do |error_key, error_messages| 
     error_messages.each do |error_message| 
     self.errors.add(error_key, error_message) 
     end 
    end 

    self.errors.to_hash.empty? 
    end 
end 

> my_model.valid_attributes? [:first_name, :email] # => returns true if first_name and email is valid, returns false if at least one is not valid 
> my_modal.errors.messages # => now contain errors of the previous validation 
{'first_name' => ["can't be blank"]}