8

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

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

4

5 回答 5

13

您可以手动验证属性并使用update_attribute,这会跳过验证。如果您将此添加到您的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

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

于 2011-08-23T03:39:09.943 回答
8

一个条件?

validates_presence_of :email, :if => :email_changed?
于 2011-08-23T06:41:10.883 回答
1

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

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

配置选项:

if - 指定要调用的方法、过程或字符串以确定是否应该进行验证(例如:if => :allow_validation 或 :if => Proc.new { |user| user.signup_step > 2 })。方法、过程或字符串应返回或评估为真或假值。

除非 - 指定要调用的方法、过程或字符串以确定是否不应该发生验证(例如 :unless => :skip_validation 或 :unless => Proc.new { |user| user.signup_step <= 2 })。方法、过程或字符串应返回或评估为真或假值。

于 2011-08-23T04:32:35.277 回答
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

希望这可以帮助。

于 2011-08-23T06:31:46.007 回答
1

这是我的解决方案。它保持与.valid 相同的行为?方法,女巫返回真或假,并在被调用的女巫的模型上添加错误。

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"]}
于 2015-01-16T16:29:17.877 回答