Я пытаюсь понять, если возможно, учитывая две модели, которые совместно используют некоторые методы и поля, поместить валидации, которые являются общими для двух из них, в абстрактный базовый класс. Ниже код представляет собой упрощенную версию моей ситуации.
Существует два класса позиций счетов-фактур: продажи и коллекции. Эти позиции имеют общее поле invoice_amount
Я хочу проверить наличие invoice_amount
из абстрактного базового класса, но подклассы проверяют поля, которые не являются общими для обеих моделей.
class Collection < InvoiceLineItem
belongs_to :invoice
validates :c_number, :invoice_number, :invoice_date, presence: true
.
.
.
end
class Sale < InvoiceLineItem
belongs_to :invoice
.
.
.
end
class InvoiceLineItem < ApplicationRecord
self.abstract_class = true
def self.inherited(base)
super
base.send(:extend, NumberFormatter)
base.send(:commafy, :invoice_amount)
end
def invoice_amount
self[:invoice_amount] || '0.00'
end
def export_date
invoice_date
end
end
Я пробовал несколько вещей, чтобы заставить это работать безуспешно. Некоторые из моих попыток включали добавление следующего кода в базовый класс InvoiceLineItem
def self.inherited(base)
base.class_eval do
validates :invoice_amount, presence: true
end
super
base.send(:extend, NumberFormatter)
base.send(:commafy, :invoice_amount)
end
и
def self.inherited(base)
base.class_eval do
base.send(:validates, :invoice_amount, presence: true)
end
super
base.send(:extend, NumberFormatter)
base.send(:commafy, :invoice_amount)
end
, и это, как описано здесь (https://medium.com/@jeremy_96642 / deep-rails- how-to-use-abstract-classes-6aee9b686e75 ), что выглядело многообещающе, потому что оно точно описывало, что я хочу сделать, однако это не работает для меня.
with_options presence:true do
validates :invoice_amount
end
Во всех этих случаях код выполняется без ошибок, однако, если я напишу тест, как показано ниже, он завершится неудачно, потому что проверка прошла успешно!
RSpec.describe Collection, type: :model do
it "Requires an invoice amount" do
result = Collection.create(invoice_amount: nil, c_number: 'CUST012', invoice_number: 'INV001', invoice_date: Date.new(1999, 1,1))
expect(result.valid?).to be false
expect(result.errors[:invoice_amount]).to include("can't be blank")
end
end
Мне не очень интересно слышать ответы о том, как это должно быть сделано с использованием композиции вместо наследования. Я не буду go в детали, но просто предположим, что это должно быть сделано с использованием наследования. Кажется, что это должно быть возможно, но я не уверен, и я не могу найти источник на inte rnet, который имеет решение, которое действительно работает.
Любая помощь будет принята с благодарностью!