Railsに組み込まれているバリデータだけでは足りなくなると、独自のバリデーションルールを書かなければならなくなります。これをやりだすとモデルがたちまち肥大化してしまうので、これを避けるにはバリデーションロジックを別クラスに切り出すのが一番です。これによってコードがすっきりと分離され、再利用しやすくなります。

class Site < ApplicationRecord
  has_one_attached :og_image
  has_one_attached :favicon
  has_many_attached :images

  validates :name, presence: true, length: { maximum: 100 }
  validates :subtitle, length: { maximum: 100 }
  validates :description, length: { maximum: 400 }
  validates :og_image, attachment: { purge: true, content_type: %r{\\Aimage/(png|jpeg)\\Z}, maximum: 524_288_000 }
  validates :favicon, attachment: { purge: true, content_type: %r{\\Aimage/png\\Z}, maximum: 524_288_000 }
  validates :images, attachment: { purge: true, content_type: %r{\\Aimage/(png|jpeg)\\Z}, maximum: 524_288_000 }
end
class AttachmentValidator < ActiveModel::EachValidator
  include ActiveSupport::NumberHelper

  def validate_each(record, attribute, value)
    return if value.blank? || !value.attached?

    has_error = false

    if options[:maximum]
      has_error = true unless validate_maximum(record, attribute, value)
    end

    if options[:content_type]
      has_error = true unless validate_content_type(record, attribute, value)
    end

    record.send(attribute).purge if options[:purge] && has_error
  end

  private

  def validate_maximum(record, attribute, value)
    if value.byte_size > options[:maximum]
      record.errors[attribute] << (options[:message] || "は#{number_to_human_size(options[:maximum])}以下にしてください") 
 #<=number_to_human_sizeはinqlude activesupport::numberhelperによって使えるメソッド
 #<=何Mbというようなファイルサイズの単位の表示に使える
      false
    else
      true
    end
  end

  def validate_content_type(record, attribute, value)
    if value.content_type.match?(options[:content_type])
      true
    else
      record.errors[attribute] << (options[:message] || 'は対応できないファイル形式です')
      false
    end
  end
end

Railsガイドより

個別の属性を検証するためのカスタムバリデータを追加するには、ActiveModel::EachValidatorを使用するのが最も簡単で便利です。この場合、このカスタムバリデータクラスはvalidate_eachメソッドを実装する必要があります。このメソッドは、

そのインスタンスに対応するレコード、(record)※これで言えばsiteのレコード

バリデーションを行う属性、(attribute)※imagesや、favicon

渡されたインスタンスの属性の値(value)※渡されたパラメータの中身の3つの引数を取ります。