You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多租户应用中基于PictureValidation属性实现ActiveStorage验证

解决方案

要实现基于租户PictureValidation表属性的动态文件大小验证,核心是解决创建Picture时如何获取当前租户的限制值问题,以下是两种可行方案:

方案一:先关联PictureValidation再创建Picture(推荐)

如果每个租户(Shop)对应唯一的PictureValidation,可以在控制器中先获取当前租户的PictureValidation,再基于它创建Picture实例,这样模型就能通过关联直接拿到限制值。

1. 控制器层处理

# app/controllers/pictures_controller.rb
class PicturesController < ApplicationController
  def create
    # 获取当前租户的PictureValidation(假设每个Shop对应一个)
    current_picture_validation = current_shop.picture_validation
    # 基于PictureValidation创建Picture,自动关联外键
    @picture = current_picture_validation.pictures.build(picture_params)
    
    if @picture.save
      redirect_to @picture, notice: 'Picture created successfully.'
    else
      render :new
    end
  end

  private

  def picture_params
    params.require(:picture).permit(:file)
  end

  # 从session获取当前租户(已存在于你的应用中)
  def current_shop
    @current_shop ||= Shop.find(session[:shop_id])
  end
end

2. 模型层动态验证

利用active_storage_validations支持的lambda参数,直接从关联的picture_validation中获取限制值:

# app/models/picture.rb
class Picture < ApplicationRecord
  has_one_attached :file
  belongs_to :picture_validation

  validates :file, attached: true, 
    size: {
      # 动态获取租户设置的大小限制,可添加默认值兜底
      less_than: ->(picture) { picture.picture_validation.size_less_than.megabytes },
      message: ->(_picture, _options) { I18n.t('is too large') }
    }
end

方案二:通过全局租户上下文传递(适用于无法提前关联的场景)

如果创建Picture时无法提前关联PictureValidation,可以通过线程安全的全局上下文传递当前租户ID,让模型直接获取对应限制。

1. 实现全局租户上下文

创建一个线程安全的类存储当前租户,避免模型直接访问session:

# app/lib/current.rb
class Current
  class << self
    attr_accessor :shop
  end
end

在控制器中设置上下文:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_current_shop

  private

  def set_current_shop
    Current.shop = Shop.find(session[:shop_id]) if session[:shop_id]
  end
end

2. 模型层自定义验证

编写自定义验证方法,从全局上下文获取租户的PictureValidation并校验文件大小:

# app/models/picture.rb
class Picture < ApplicationRecord
  has_one_attached :file
  belongs_to :picture_validation

  validate :enforce_tenant_file_size_limit

  private

  def enforce_tenant_file_size_limit
    return unless file.attached? && Current.shop.present?

    picture_validation = Current.shop.picture_validation
    return unless picture_validation&.size_less_than

    max_size = picture_validation.size_less_than.megabytes
    if file.byte_size > max_size
      errors.add(:file, I18n.t('is too large'))
    end
  end
end

注意事项

  • 确保每个Shop都有对应的PictureValidation记录,避免出现nil导致验证失效;
  • 可以给size_less_than设置默认值(比如5.megabytes),防止租户未配置时验证报错;
  • 全局上下文方案要注意线程安全,避免多租户请求互相干扰。

内容的提问来源于stack exchange,提问作者Jerome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:47:24