验证和更新单个属性rails

时间:2011-08-23 03:36:29

标签: ruby-on-rails activerecord rails-activerecord

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

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]),但这也会跳过头像字段的验证。

5 个答案:

答案 0 :(得分: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?仅查看您感兴趣的属性的验证失败。

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

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

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

答案 1 :(得分:8)

条件?

validates_presence_of :email, :if => :email_changed?

答案 2 :(得分:1)

您是否尝试过在validates_presence_of :email上添加条件?

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

配置选项:

  

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

     

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

答案 3 :(得分: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

希望这有帮助。

答案 4 :(得分: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"]}