проверять и обновлять рельсы с одним атрибутом - PullRequest
8 голосов
/ 23 августа 2011

У меня в моей пользовательской модели следующее

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 ]

13 голосов
/ 23 августа 2011

Вы можете проверить атрибут вручную и использовать 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])

Вы должны обновить свой единственный атрибут, пока только(вручную) проверка этого атрибута.

Если вы посмотрите, как работает valid_attribute? Milan Novota, вы увидите, что он выполняет проверки, а затем проверяет, есть ли у конкретных 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

и использовать его для обновления вашего единственного атрибута.

8 голосов
/ 23 августа 2011

Состояние?

validates_presence_of :email, :if => :email_changed?
1 голос
/ 16 января 2015

Вот мое решение.Он сохраняет то же поведение, что и метод .valid? , witch возвращает 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"]}
1 голос
/ 23 августа 2011

Я предполагаю, что вам это нужно, потому что у вас есть многошаговый мастер, где вы сначала загружаете аватар, а электронная почта заполняется позже.

Насколько мне известно, с вашими утверждениями, как они есть, я не вижу хорошего рабочего решения. Либо вы подтверждаете все, либо вы обновляете аватар без проверок. Если бы это был простой атрибут, вы могли бы проверить, проходит ли новое значение проверку отдельно, а затем обновить модель без проверок (например, используя 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

Надеюсь, это поможет.

1 голос
/ 23 августа 2011

Вы пытались поставить условие на 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}).Метод, метод или строка должны возвращать или оценивать истинное или ложное значение.

исключением - указывает метод, метод или строку, которые необходимо вызвать, чтобы определить, не должна ли происходить проверка (например,:или: кроме случаев, когда => Proc.new {| user | user.signup_step <= 2}).Метод, процедура или строка должны возвращать или оценивать истинное или ложное значение. </p>

...