简体   繁体   中英

Include module contionally in Rails

Consider multiple ActiveRecord classes with overlapping fields and functionality and many of those overlapping fields having the same validation. I'm attempting to share validation, but not run the shared code if a condition is met (based on one of the Model's non-overlapping attributes).

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

So let's say Magazine.is_deleted is a Magazine-only field and we only want to run shared validations if is_deleted is false . Any ideas on how this could be accomplished in the Class?


Note: I've attempted to modify the module by performing field detection and evaluation, but am not sure if this makes sense or if it's working:

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

It looks like instead of including the module conditionally, you can add the conditional to the validation methods (within the SharedModule).

Using your samples:

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

Magazine has name , publisher and is_deleted columns. Book only has name , publisher - without is_deleted .

And it looks like this setup works.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM