有条件地在 Rails 中包含模块

Include module contionally in Rails

考虑具有重叠字段和功能的多个 ActiveRecord 类,并且其中许多重叠字段具有相同的验证。我正在尝试共享验证,但如果满足条件(基于模型的非重叠属性之一),则 运行 不共享代码。

class Book < ApplicationRecord
  include SharedValidation
end

class Magazine < ApplicationRecord
  include SharedValidation
end

module SharedValidation
  extend ActiveSupport::Concern
  include ActiveModel::Validations

  validates_presence_of :name, :publisher, :author
end

假设 Magazine.is_deleted 是一个仅限杂志的字段,如果 is_deleted 为 false,我们只想 运行 共享验证。关于如何在 Class?

中实现这一点的任何想法

注意:我试图通过执行现场检测和评估来修改模块,但不确定这是否有意义或是否有效:

module SharedValidation
  extend ActiveSupport::Concern
  include ActiveModel::Validations

  included do
    proc do |rcd|
      has_deleted_field = self.column_names.include?('is_deleted') 
      
      if (has_deleted_field && !rcd.is_deleted) || !has_deleted_field
        validates_presence_of :name, :publisher, :author
      end 
    end
  end
end

看起来您可以将条件添加到验证方法(在 SharedModule 中),而不是有条件地包含模块。

使用您的样本:

class Book < ApplicationRecord
  include SharedValidations
end

class Magazine < ApplicationRecord
  include SharedValidations
end

module SharedValidations
  extend ActiveSupport::Concern
  include ActiveModel::Validations

  def deleted
    return unless self.class.column_names.include?("is_deleted")

    is_deleted
  end

  included do
    validates :name, :publisher, presence: true, unless: :deleted
  end
end

杂志有 namepublisheris_deleted 栏。 书只有 name , publisher - 没有 is_deleted.

看起来这个设置有效。

irb> book = Book.new()
=> #<Book id: nil, name: nil, publisher: nil, created_at: nil, updated_at: nil>
irb> book.valid?
=> false
irb> book.errors.full_messages
=> ["Name can't be blank", "Publisher can't be blank"]

irb> magazine = Magazine.new
=> #<Magazine id: nil, name: nil, publisher: nil, is_deleted: nil, created_at: nil, updated_at: nil>
irb> magazine.valid?
=> false
irb> magazine.errors.full_messages
=> ["Name can't be blank", "Publisher can't be blank"]

irb> magazine.is_deleted=true
=> true
irb> magazine.valid?
=> true