Erik Madsen
Erik Madsen

Reputation: 2014

Use Paperclip validations without storing the attachment

I am building a Rails endpoint that proxies a different service and maps the responses from said service. The main problem is to pass along a file attachment's byte data to that service.

A constraint is that I must do some sanity checks on the file before I pass it along.

I have no need to persist the file in my Rails app, it is merely used as input to the other service.

In a very simple implementation I simply just read the bytes from the appropriate request parameter which is wrapped in a Tempfile, but this of course entails no sanity checks, and therefore is not good enough.

I am interested in doing the kinds of validation that Paperclip supports, in particular size and content type, but I would prefer to not store the actual file anywhere.

Is it possible to use only the validation parts of Paperclip and not store the attachment anywhere?

Upvotes: 1

Views: 283

Answers (2)

Erik Madsen
Erik Madsen

Reputation: 2014

This is how I ended up solving it, heavily inspired by https://gist.github.com/basgys/5712426

Since my project was already using Paperclip, I went for a solution based on that rather than including more gems.

First, a non-persisted model like so:

class Thumbnail
  extend ActiveModel::Callbacks
  include ActiveModel::Model
  include Paperclip::Glue

  ALLOWED_SIZE_RANGE = 1..1500.kilobytes.freeze
  ALLOWED_CONTENT = ['image/jpeg'].freeze

  # Paperclip required callbacks
  define_model_callbacks :save, only: [:after]
  define_model_callbacks :destroy, only: %i(before after)

  attr_accessor :image_file_name,
                :image_content_type,
                :image_file_size,
                :image_updated_at,
                :id

  has_attached_file :image
  validates_attachment :image,
                       presence: true,
                       content_type: { content_type: ALLOWED_CONTENT },
                       size: { in: ALLOWED_SIZE_RANGE }

  def errors
    @errors ||= ActiveModel::Errors.new(self)
  end
end

Then, wrap the incoming image file in that model from the controller:

class SomeController < ApplicationController
  before_action :validate_thumbnail

  def some_action
    some_service.send(image_data)
  end


  private

  def thumbnail
    @thumbnail ||= Thumbnail.new(image: params.require(:image))
  end    

  def validate_thumbnail
    render_errors model: thumbnail if thumbnail.invalid?
  end

  def image_data
    Paperclip.io_adapters.for(thumbnail.image).read
  end

  def some_service
    # memoized service instance here
  end   
end

Upvotes: 2

Aschen
Aschen

Reputation: 1771

You can verify the file mime-type with the gem ruby-filemagic :

FileMagic.new(FileMagic::MAGIC_MIME).file(your_tempfile.path) #=> "image/png; charset=binary"

For the size you could just check with your_tempfile.size

Upvotes: 1

Related Questions