activestorage-validator

repository·master·Indexed 42 days ago

https://github.com/aki77/activestorage-validator

A Rails gem providing validations for ActiveStorage attachments. It allows developers to enforce constraints on content_type, file size (size_range), and file extensions for both has_one_attached and has_many_attached attributes using a blob validator.

Tokens
3.8K
Snippets
8
Records
13
Agent score
32%

What's inside activestorage-validator

  1. Use the blob validator for ActiveStorage attachments

    master

    To validate has_one_attached or has_many_attached attachments, use the blob validator within your Rails model.

    Note: For has_many_attached, the size_range validation is applied to each file individually.

    class User < ApplicationRecord
      has_one_attached :avatar
      has_many_attached :photos
    
      # Allow only web image files (PNG, JPEG, GIF, WebP)
      validates :avatar, presence: true, blob: { content_type: :web_image }
    
      # Allow only JPEG/PNG, up to 5MB per file
      validates :photos, presence: true, blob: { content_type: ["image/png", "image/jpg", "image/jpeg"], size_range: 1..(5.megabytes) }
    
      # Require specific file extensions
      validates :audio, blob: { content_type: "audio/mpeg", extension: %w[mp3] }
    end
    class User < ApplicationRecord
      has_one_attached :avatar
      has_many_attached :photos
    
      # Allow only web image files
      validates :avatar, presence: true, blob: { content_type: :web_image }
    
      # Allow only JPEG/PNG, up to 5MB per file
      validates :photos, presence: true, blob: { content_type: ["image/png", "image/jpg", "image/jpeg"], size_range: 1..(5.megabytes) }
    end
  2. How to use activestorage-validator for ActiveStorage attachments

    master

    The activestorage-validator gem provides a blob: validator to verify ActiveStorage attachments (content type, file size, and extension) for both has_one_attached and has_many_attached attributes.

    Important distinction: This validator is specifically for ActiveStorage blobs. For standard model attributes (strings, numbers, booleans), use standard Rails validators like presence, length, or numericality. To make an attachment required, combine presence: true with the blob: validator.

    class User < ApplicationRecord
      has_one_attached :avatar
      has_many_attached :photos
    
      # Example: Allow only web images (PNG, JPEG, GIF, WebP)
      validates :avatar, presence: true, blob: { content_type: :web_image }
    
      # Example: JPEG/PNG only, 1 to 5MB per file
      validates :photos, presence: true, blob: {
        content_type: ["image/png", "image/jpg", "image/jpeg"],
        size_range: 1..(5.megabytes)
      }
    
      # Example: Regexp content_type AND specific extension (AND condition)
      validates :audio, blob: { content_type: "audio/mpeg", extension: %w[mp3] }
    end
  3. How to use the `blob:` validator for ActiveStorage

    master

    The activestorage-validator gem provides a blob: validator to validate ActiveStorage attachments (has_one_attached or has_many_attached). It allows you to enforce constraints on content type, file size, and file extensions.

    Key Usage Rules

    • Applicability: Use blob: only for ActiveStorage attachments. For standard database columns (strings, integers, etc.), use standard Rails validators like presence or length.
    • Presence: The blob: validator skips unattached values. To make an attachment mandatory, you must combine it with presence: true.
    • has_many_attached: For collections, every validation option (including size_range) is applied to each file individually, not the total size of the collection.
    • Execution: It is a standard EachValidator that runs during the normal Rails save or valid? lifecycle.
    class User < ApplicationRecord
      has_one_attached :avatar
      has_many_attached :photos
    
      # Allow only web image files (PNG, JPEG, GIF, WebP)
      validates :avatar, presence: true, blob: { content_type: :web_image }
    
      # Allow only JPEG/PNG, up to 5MB per file
      validates :photos, presence: true, blob: {
        content_type: ["image/png", "image/jpg", "image/jpeg"],
        size_range: 1..(5.megabytes)
      }
    
      # Regexp content_type + required extension (AND condition)
      validates :audio, blob: { content_type: "audio/mpeg", extension: %w[mp3] }
    end
  4. Use Procs for dynamic validation options

    master

    All validation options (size_range, content_type, and extension) can be passed as a Proc to allow for dynamic validation logic based on the record instance. The validator follows standard Rails arity conventions:

    • Arity 0: The proc is called without arguments (value.call).
    • Arity 1: The record instance is passed as an argument (value.call(record)).

    This allows you to change validation constraints based on other attributes of the model.

    # Example: Dynamic size range based on a user's subscription level
    validates :document, blob: {
      size_range: ->(record) { record.premium? ? 0..100.megabytes : 0..5.megabytes }
    }
  5. Troubleshoot `blob:` validator pitfalls

    master

    When using the blob: validator, be aware of the following behaviors:

    • Missing Extensions: If you set the extension: option, any file without an extension will be rejected, even if its content_type is valid. Do not use extension: if you want to allow extension-less uploads.
    • Mandatory Attachments: The blob: validator does not enforce that an attachment exists; it only validates the attachment if it is present. Always pair it with presence: true if the file is required.
    • Collection Size: For has_many_attached, the size_range applies to each individual file, not the cumulative size of all files in the attachment.
    • Size Boundaries: The size_range is inclusive (min <= size <= max).
  6. Troubleshoot blob validation behavior

    master

    Keep these implementation details in mind to avoid common mistakes:

    • Missing Attachments: The blob: validator skips validation if no attachment is present. It does not enforce presence. Use presence: true if the attachment is required.
    • has_many_attached Scoping: For collections, size_range and other options are applied to each individual file, not the total size of the collection.
    • Extension Rejection: If you specify extension:, any file without an extension will be rejected, even if its content_type is valid. If you want to allow files without extensions, omit the extension option.
    • Size Boundaries: The size_range is inclusive (min <= size <= max).
    • Execution Timing: Validation occurs during standard Rails valid? or save calls; no special loading or preloading is required.
  7. Configure blob validation options

    master

    The blob: validator accepts three optional keys. All options can accept a Proc/lambda that follows standard Rails validator arity (e.g., ->(record) { ... } receives the record). In has_many_attached, Procs are evaluated once per file.

    OptionAccepted TypesDescription
    content_typeSymbol / Array / Regexp / String / ProcValidates the MIME type.
    size_rangeRange / ProcValidates byte size (inclusive). Example: 1..(5.megabytes).
    extensionString / Array / ProcValidates the file extension.

    content_type matching rules

    • :web_image: Special shortcut for ActiveStorage.web_image_content_types (PNG, JPEG, GIF, WebP).
    • Other Symbols (:image, :audio, :video, :text): Calls ActiveStorage predicates like blob.image?.
    • Array: Checks if the blob's content type is included in the list.
    • Regexp: Matches the content type against the pattern.
    • String: Performs an exact match.

    extension matching rules

    • Accepts a String ("mp3") or Array (%w[mp3 m4a]).
    • Leading dots are optional ("mp3" and ".mp3" are treated identically).
    • Case-insensitive (e.g., "jpg" matches PHOTO.JPG).
    • Note: Files without an extension are always rejected if this option is present.
    • When used with content_type, both must match (AND logic).
  8. Configure `blob:` validator options

    master

    The blob: validator accepts several optional parameters to constrain attachments. All options can be combined freely and can also accept a Proc/lambda for dynamic validation.

    Available Options

    OptionAcceptsNotes
    content_typeSymbol / Array / Regexp / String / ProcAllowed MIME type(s).
    size_rangeRange / ProcAllowed byte size (e.g., 1..(5.megabytes)).
    extensionString / Array / ProcAllowed filename extension(s).

    Content Type Matching

    • :web_image: Special symbol for browser-safe images (PNG, JPEG, GIF, WebP).
    • Other Symbols: :image, :audio, :video, :text (calls ActiveStorage predicates like blob.image?).
    • Array: ["image/png", "image/jpeg"] (exact membership).
    • Regexp: %r{^image/} (matches against the MIME type string).
    • String: "application/pdf" (exact equality).

    Extension Matching

    • Accepts a String ("mp3") or Array (%w[mp3 m4a]).
    • Leading dots are optional ("mp3" matches ".mp3").
    • Matching is case-insensitive.
    • Warning: A file with no extension is always rejected if the extension option is set.
    • When used with content_type, both must pass (AND condition).
  9. Customize `blob:` validator I18n error messages

    master

    The gem is I18n-compatible. You can override the default error messages in your application's locale files (e.g., config/locales/en.yml).

    Error Types and Interpolation Keys

    Error typeInterpolation keysDescription
    content_typefilenameContent type not allowed
    min_size_errorfilename, min_sizeSmaller than size_range.min
    max_size_errorfilename, max_sizeLarger than size_range.max
    extensionfilename, extensionExtension not allowed or missing

    Note: min_size and max_size are humanized using ActiveSupport::NumberHelper.number_to_human_size.

    # config/locales/en.yml
    en:
      errors:
        messages:
          content_type: "%{filename} has an invalid content type"
          min_size_error: "%{filename} is too small (minimum is %{min_size})"
          max_size_error: "%{filename} is too large (maximum is %{max_size})"
          extension: "%{filename} has an invalid file extension (allowed: %{extension})"
  10. Customize I18n error messages for blob validation

    master

    The validator is I18n-ready. You can override the default messages (which are provided in 7 languages including en and ja) by using the following error types and interpolation keys in your locale files.

    Error TypeInterpolation KeysCondition
    content_typefilenameContent type is not allowed
    min_size_errorfilename, min_sizeSize is smaller than size_range.min
    max_size_errorfilename, max_sizeSize is larger than size_range.max
    extensionfilename, extensionExtension is not allowed or missing

    min_size and max_size are humanized using ActiveSupport::NumberHelper.number_to_human_size. extension is a comma-separated string of allowed extensions.

    # Example config/locales/ja.yml
    ja:
      errors:
        messages:
          content_type: "%{filename}のコンテンツタイプが正しくありません"
          min_size_error: "%{filename}が小さすぎます(最小%{min_size})"
          max_size_error: "%{filename}が大きすぎます(最大%{max_size})"
          extension: "%{filename}の拡張子が正しくありません(許可: %{extension})"
  11. Configure ActiveStorage blob validations

    master

    Use the blob: option within Rails model validations to validate attached files. The BlobValidator supports three primary validation keys: size_range, content_type, and extension.

    Validation Options

    • size_range: A Range object defining the minimum and maximum allowed byte_size. If validation fails, it adds :min_size_error or :max_size_error to the record's errors.
    • content_type: Validates the file's MIME type. It accepts:
      • Regexp: Matches against the blob's content_type.
      • Array: Checks if the blob's content_type is included in the list.
      • :web_image: A special symbol that checks against ActiveStorage.web_image_content_types.
      • Symbol: Calls a predicate method on the blob (e.g., :image? calls blob.image?).
      • String: Performs an exact match against the content_type.
    • extension: Validates the file extension. It accepts an Array of strings or a single string. Extensions are normalized (case-insensitive and leading dots are removed).
    # Example: Allow only web images, JPEG/PNG up to 5MB, with specific extensions
    validates :photos, blob: {
      content_type: :web_image,
      size_range: 1..(5.megabytes),
      extension: %w[jpg jpeg png]
    }
    
    # Example: Using a Regular Expression for content type
    validates :audio, blob: { content_type: %r{^audio/}, size_range: 0..10.megabytes }