Skip to content

Instantly share code, notes, and snippets.

@basgys
Created June 5, 2013 08:25
Show Gist options
  • Save basgys/5712426 to your computer and use it in GitHub Desktop.
Save basgys/5712426 to your computer and use it in GitHub Desktop.
Use Paperclip without ActiveRecord
# == Paperclip without ActiveRecord
#
# Simple and lightweight object that can use Paperclip
#
#
# Customized part can be extracted in another class which
# would inherit from SimplePaperclip.
#
# class MyClass < SimplePaperclip
# attr_accessor :image_file_name # :<atached_file_name>_file_name
# has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
#  end
#
# author : Bastien Gysler <[email protected]>
class SimplePaperclip
extend ActiveModel::Naming
extend ActiveModel::Callbacks
include ActiveModel::Validations
include Paperclip::Glue
# Paperclip required callbacks
define_model_callbacks :save, only: [:after]
define_model_callbacks :destroy, only: [:before, :after]
# Paperclip attached file example
# -- Customize here --
attr_accessor :image_file_name # :<atached_file_name>_file_name
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
# -- /Customize here --
# ActiveModel requirements
def to_model
self
end
def valid?() true end
def new_record?() true end
def destroyed?() true end
def errors
obj = Object.new
def obj.[](key) [] end
def obj.full_messages() [] end
obj
end
end
@charlotte-miller
Copy link

Awesome work, one update: paperclip 3.5.1 requires errors.any?

  def errors
    obj = Object.new
    def obj.[](key)         [] end
    def obj.full_messages() [] end
    def obj.any?()       false end
    obj
  end 

@jgrahamthomas
Copy link

Made some slight updates to get things to jive with Rails 4. Note with the example above, the 'save' method wasn't defined, nor were the callbacks being invoked.

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

  # Paperclip required callbacks
  define_model_callbacks :save, only: [:after]
  define_model_callbacks :destroy, only: [:before, :after]

  attr_accessor :photo_file_name, :photo_content_type, :photo_file_size, :photo_updated_at, :id

  has_attached_file :photo, :styles => { :thumb => ["100x100#", :png], :small => ["200x200#", :png], :cover => ["1300x528#", :png] },  :processors => [:auto_orient, :thumbnail]

  def save
    run_callbacks :save do 
      self.id = 1000 + Random.rand(9000)
    end
    return true
  end

  def destroy
    run_callbacks :destroy
  end

  def updated_at_short
    return Time.now.to_s(:autosave_time) 
  end

  def errors
    obj = Object.new
    def obj.[](key)         [] end
    def obj.full_messages() [] end
    def obj.any?()       false end
    obj
  end 
end

@jgrahamthomas
Copy link

Had to make a slight update since upgrading to Paperclip 4.1.1. Note the inclusion of "do_not_validate_attachment_file_type":

# This class behaves like an ActiveRecord object so we can take full
# advantage of paperclip.  But it ain't a real AR object!  Nice piece
# of trickery here.
class PublishableItemImage
  extend ActiveModel::Callbacks
  include ActiveModel::Model
  include Paperclip::Glue

  # Paperclip required callbacks
  define_model_callbacks :save, only: [:after]
  define_model_callbacks :commit, only: [:after]
  define_model_callbacks :destroy, only: [:before, :after]

  attr_accessor :photo_file_name, :photo_content_type, :photo_file_size, :photo_updated_at, :id

  has_attached_file :photo, :styles => { :thumb => ["100x100#", :png], :small => ["200x200>", :png], :cover => ["1300x528>", :png] },  :processors => [:auto_orient, :thumbnail]
  do_not_validate_attachment_file_type :photo

  def save
    run_callbacks :save do 
      self.id = 1000 + Random.rand(9000)
    end
    return true
  end

  def destroy
    run_callbacks :destroy
  end

  def updated_at_short
    return Time.now.to_s(:autosave_time) 
  end

  def errors
    obj = Object.new
    def obj.[](key)         [] end
    def obj.full_messages() [] end
    def obj.any?()       false end
    obj
  end 
end

@thedanielhanke
Copy link

👍 thanks for sharing!

@em77
Copy link

em77 commented Jul 11, 2016

Hey @jgrahamthomas, what's the deal with the inclusion of do_not_validate_attachment_file_type? I'm using this code now and I'm noticing that if instead I try using a normal validation method I'd usually use with paperclip on an activerecord object like validates_attachment_content_typeit's giving me a NoMethodError of undefined method 'add' for #<Object:0x007f7fa5e88d80>. If I use your way above, it works, but is there any way to do validations with this? I'd like to have some degree of validation of the files being uploaded. Thanks for your contributions on this so far!

@posixpascal
Copy link

Why self.id = Random? Wouldn't be a timestamp + random a better solution?

@tahsin352
Copy link

tahsin352 commented Apr 8, 2022

class Whitelabel
  extend ActiveModel::Naming
  extend ActiveModel::Callbacks

  include ActiveModel::Model
  include ActiveModel::Validations
  include ActiveModel::Conversion
  include ActionView::Helpers::SanitizeHelper
  include Paperclip::Glue

  define_model_callbacks :save
  define_model_callbacks :destroy

  has_attached_file :logo, url: "/system/:hash.:extension", hash_secret: "longSecretString", styles: { thumb: ["300x300#", :jpeg], original: [:jpeg] }
  #validates_attachment_content_type :logo, content_type: /\Aimage\/[svg+xml|jpg]\z/, message: "File format of attachment is invalid. Please attach an image."
  validates_attachment :logo, presence: true, content_type: { content_type: ["image/jpg", "image/png", "image/gif"] }
  #validate :no_attachement_errors

  attr_accessor :id, :logo_file_name, :logo_file_size, :logo_content_type, :logo_updated_at

  def initialize(args = { })
    args.each_pair do |k, v|
      self.send("#{k}=", v)
    end
    @id = self.class.next_id
  end

  def update_attributes(args = { })
    args.each_pair do |k, v|
      self.send("#{k}=", v)
    end
  end

  def save
    run_callbacks :save do
    end
  end

  def unscoped
    run_callbacks :unscoped do
    end
  end

  def destroy
    run_callbacks :destroy do
    end
  end

  # Need a differentiating id for each new Importer.
  def self.next_id
    @@id_counter += 1
  end

  # Initialize beginning id to something mildly unique.
  @@id_counter = Time.now.to_i

end

Getting this error

NoMethodError: undefined method `unscoped' for Whitelabel:Class
/Users/admin/.rvm/gems/ruby-2.7.1/gems/paperclip-6.1.0/lib/paperclip/helpers.rb:41:in `each_instance_with_attachment'
/Users/admin/.rvm/gems/ruby-2.7.1/gems/paperclip-6.1.0/lib/tasks/paperclip.rake:66:in `block (4 levels) in <main>'
/Users/admin/.rvm/gems/ruby-2.7.1/gems/paperclip-6.1.0/lib/tasks/paperclip.rake:65:in `each'
/Users/admin/.rvm/gems/ruby-2.7.1/gems/paperclip-6.1.0/lib/tasks/paperclip.rake:65:in `block (3 levels) in <main>'
/Users/admin/.rvm/gems/ruby-2.7.1/gems/rake-13.0.6/exe/rake:27:in `<top (required)>'
/Users/admin/.rvm/gems/ruby-2.7.1/bin/ruby_executable_hooks:22:in `eval'
/Users/admin/.rvm/gems/ruby-2.7.1/bin/ruby_executable_hooks:22:in `<main>'
Tasks: TOP => paperclip:refresh => paperclip:refresh:metadata
(See full trace by running task with --trace)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment