2011-08-23 77 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"]}