validation和更新单个属性rails

我的用户模型中有以下内容

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? } 

在我的一个控制器中, 我只想更新和validation头像字段而不更新和validation电子邮件

我怎样才能做到这一点?

例如(这不起作用)

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

我也尝试过update_attribute('avatar', params[:user][:avatar]) ,但这也会跳过avatar字段的validation。

您可以手动validation属性并使用update_attribute来跳过validation 。 如果您将此添加到您的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]) 

只有(手动)validation该属性时,才应更新单个属性。

如果你看一下Milan Novota的valid_attribute? 工作,你会看到它执行validation,然后检查特定的attr是否有问题; 是否有任何其他validation作为valid_attribute?失败并不重要valid_attribute? 仅查看您感兴趣的属性的validation失败。

如果您要做很​​多这样的事情,那么您可以向用户添加一个方法:

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

并使用它来更新您的单个属性。

一个条件?

 validates_presence_of :email, :if => :email_changed? 

您是否尝试过在validates_presence_of :email上设置条件validates_presence_of :email

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

配置选项:

if – 指定要调用的方法,proc或字符串,以确定是否应进行validation(例如:if =>:allow_validation,或:if => Proc.new {| user | user.signup_step> 2})。 方法,proc或string应返回或计算为true或false值。

除非 – 指定要调用的方法,proc或字符串,以确定是否不应进行validation(例如:unless =>:skip_validation,或:unless => Proc.new {| user | user.signup_step <= 2})。 方法,proc或string应返回或计算为true或false值。

我假设你需要这个,因为你有一个多步向导,你首先上传头像,电子邮件稍后填写。

据我所知,通过您的validation,我认为没有好的工作解决方案。 要么全部validation,要么在没有validation的情况下更新头像。 如果它是一个简单的属性,您可以检查新值是否单独通过validation,然后更新模型而不进行validation(例如,使用update_attribute )。

我可以建议两种可能的替代方法:

  • 要么你确保首先输入电子邮件,我认为这不是一个糟糕的解决方案。 然后,每次保存,都会得到validation。
  • 否则,更改validation。 如果数据库中有不符合validation的记录,为什么要在模型上声明validation? 这非常违反直觉。

所以我建议这样的事情:

 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 

希望这可以帮助。

这是我的解决方案。 它保持与.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"]}