Как вручную вызвать ActiveRecord RecordInvalid в Rails - PullRequest
1 голос
/ 21 июня 2020

Запись: У меня есть класс атрибута, производный от одного из типов ActiveRecord, и реализующий метод cast (value), который преобразует предоставленное значение в производный тип Active Record. В нашем случае мы выполняем преобразование только тогда, когда предоставленное значение является String, в противном случае выполняется целочисленное приведение по умолчанию. Частный метод to_minutes преобразует форматированное время в целое число, представляющее затраченные минуты. Я предположил, что 1d = 8h = 480m. Например, результат to_minutes ('1d 1h 1m') = 541. (Я использовал этот ресурс Custom Attributes в Ruby on Rails 5 ActiveRecord

Если пришел string не имеет номеров, мне нужно вернуть ошибку проверки и установить для этой ошибки значение @card.errors. Как мне это сделать? Я пытаюсь:

if time.scan(/\d/).empty?
  raise ActiveRecord::RecordInvalid.new(InvalidRecord.new)
end

Но это не работает, я получаю сообщение об ошибке

NameError in CardsController#update
uninitialized constant CardDuration::Type::InvalidRecord
Extracted source (around line #15):

Я создаю свой собственный атрибут для целочисленного типа:

class CardDuration
  class Type < ActiveRecord::Type::Value
    def cast(value)
      if value.is_a?(String)
        to_seconds(value)
      else
        super
      end
    end

    private

    def to_seconds(time)
      if time.scan(/\d/).empty?
           return raise ActiveRecord::RecordInvalid.new, { errors: {message: 'Duration is too short (minimum is 1 number)'} }
      end
      time_sum = 0
      time.split(' ').each do |time_part|
        value = time_part.to_i
        type = time_part[-1,1]
        case type
        when 'm'
          value
        when 'h'
          value *= 60
        when 'd'
          value *= 8*60
        else
          value
        end
        time_sum += value
      end
      time_sum
    end
  end
end

и внутри модели:

class Card < ApplicationRecord
  validates :duration,  length: { within: 0..14880 }
  attribute :duration, CardDuration::Type.new
end

Также проверка не работает, и я делаю не понимаю почему. Спасибо) Внутри контроллера это поле можно только обновлять, поэтому мне нужно установить ошибку на @ card.errors:

class CardsController < ApplicationController
  def update
    if @card.update(card_params)
      flash[:success] = "Card was successfully updated."
    else
      flash[:error] = @card.errors.full_messages.join("\n")
      render status: 422
    end
    rescue ActiveRecord::RecordInvalid => e
      return e.record
  end
end

Ответы [ 2 ]

1 голос
/ 21 июня 2020

в ActiveRecord :: RecordInvalid.new (...) вам необходимо передать структуру, в которой есть метод «ошибки» документация . попробуйте raise ActiveRecord::RecordInvalid.new(self.new) или написать или создать собственный класс с методом errors, который будет обрабатывать ваши исключения

0 голосов
/ 21 июня 2020

Единственная проблема, которую я вижу в вашем коде, - это то, как вы вызываете ошибку недопустимой записи.

Правильный способ сделать это -

raise ActiveRecord::RecordInvalid

...