Запись: У меня есть класс атрибута, производный от одного из типов 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