Общие проверки модели Rails, унаследованные от абстрактного базового класса, но уникальные проверки полей происходят на подклассе

Я пытаюсь понять, возможно ли, учитывая две модели, которые совместно используют некоторые методы и поля, поместить валидации, которые являются общими для двух из них, в абстрактный базовый класс. Ниже код представляет собой упрощенную версию моей ситуации.

Существует два класса позиций счетов-фактур: продажи и коллекции. Эти позиции имеют общее поле 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] || Ɔ.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

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

Любая помощь будет очень высоко ценится!

Всего 1 ответ


Я понял мою проблему, оказывается, этот код работал:

class InvoiceLineItem < ApplicationRecord
  self.abstract_class = true

  def self.inherited(base)
    super
    base.send(:extend, NumberFormatter)
    base.send(:commafy, :invoice_amount)
  end

  with_options presence: true do
    validates :invoice_amount
  end

  def invoice_amount
    self[:invoice_amount] || 0.00
  end

  def export_date
    invoice_date
  end

  def debtor_number_up_to_space
    debtor_number.split[0]
  end
end

Валидатор использовал метод invoice_amount который invoice_amount поле в модели, поэтому invoice_amount воспринимался не как nil а как 0.00 поэтому проверка моего теста прошла правильно.

Однажды я удалил || 0.00 || 0.00 Я мог бы сдать тест.


Есть идеи?

10000