GitXplorerGitXplorer
k

storage

public
12 stars
0 forks
0 issues

Commits

List of commits on branch master.
Unverified
353348def6a752194e3663584f1d249d0a114633

Minor

kkirs committed 10 years ago
Unverified
b7d197074425a45e1b1713b724927d89c86fcea3

Mixed storage support

kkirs committed 10 years ago
Unverified
4ae8a259d9f9bd454b334dcce4f9e75354346450

Handle bad URLs and filenames

kkirs committed 10 years ago
Unverified
2af167aaf532a4c7424b2127cab30720025758b7

Better API in model key

kkirs committed 10 years ago
Unverified
9206296904a6ffdfb8fc7a33f3274ddd83764de3

Reworked storage key

kkirs committed 10 years ago
Unverified
4954ca11100b5e03f33997c2fe520788257876ec

Pass version to model_uploads_path

kkirs committed 10 years ago

README

The README file for this repository.

Storage

Build Status Code Climate

At Evil Martians, we use Carrierwave to store billions of files in S3 cloud and we faced with such issues:

So what we need, is the solution to:

  • download remote image
  • save it locally
  • process it (including resize and watermarks)
  • transfer it to S3 in background if we need to
  • backup it
  • reprocess photo if size was changed

Installation

Add this line to your application's Gemfile:

gem 'storage'

And then execute:

$ bundle

Or install it yourself as:

$ gem install storage

Then you can configure Storage in Rails initializer:

# config/initializers/storage.rb
Storage.setup do |config|
  secrets = Rails.application.secrets[:s3]
  if secrets.nil?
    raise ArgumentError.new("secrets.yml doesn't have credentials for S3")
  end

  # only if you use Amazon S3
  config.s3_credentials = {
    access_key_id: secrets['access_key'],
    secret_access_key: secrets['secret_key'],
    region: secrets['region']
  }

  # only if you use Amazon S3
  config.bucket_name = "my-app_#{Rails.env}"
end

Usage

Firstly, you need to declare Storage model (almost like Uploader you used in CarrierWave):

# app/storages/cover_photo_storage.rb
class CoverPhotoStorage < Storage::Model
  version :original
  version :thumb, size: "200x200"
  version :big, size: "300x300"

  # leave this if you want to use S3 as a storage
  store_remotely

  # define how you would like to modify the image
  def process_image(version, image)
    # image is original, instance of MiniMagick::Image
    # you can transform existing image object or return the new one
    if version.options[:size].present?
      image.resize(version.options[:size])
    end
  end

  # optionally: redefine to use custom uploads path
  # default is: /uploads/:model_name/:id/:field/:version_name/:filename
  def key(version, filename)
    File.join("uploads", model.class.name.underscore, model.id.to_s, field_name, version, filename)
  end
end

And then mount CoverPhotoStorage into your model:

# app/models/post.rb
class Post < ActiveRecord::Base
  def cover_photo
    @cover_photo ||= CoverPhotoStorage.new(self, :cover_photo)
  end
end

Don't forget to add cover_photo column into your DB scheme

Now you can use Storage API:

post = Post.create!
post.cover_photo.download("http://example.com/photo.jpg")
post.cover_photo.present?
=> true
post.cover_photo.url
=> 'https://yourbucker.s3-eu-west-1.amazonaws.com/uploads/post/1/original/photo.jpg'
post.cover_photo.url(:big)
=> 'https://yourbucker.s3-eu-west-1.amazonaws.com/uploads/post/1/big/photo.jpg'
post.cover_photo.remove
=> true
post.cover_photo.present?
=> false

post.cover_photo.store(File.open('/var/www/somefile.jpg'))

# or store with custom name:
post.cover_photo.store(File.open('/var/www/somefile.jpg'), filename: 'photo.jpg')

post.cover_photo.present?
=> true
post.cover_photo.local_path
=> /path/to/rails/public/uploads/post/1/big/photo.jpg

# to reprocess all records
Post.find_each do |post|
  post.cover_photo.reprocess
end

Alias AWS S3 URLs

You may want to proxy/alias S3 assets throught your servers to hide original URL or to reduce S3 trafic using caching.

It's easy to write your own Remote backend:

class CustomRemote < Storage::Remote
  def url_for(filename, with_protocol: false)
    protocol_prefix = if with_protocol
      "http:"
    else
      ""
    end

    "#{protocol_prefix}//storage.yourcompany.com/#{filename}"
  end
end
class PhotoStorage < Storage::Model
  version :original
  version :big

  def remote_klass
    CustomRemote
  end
end
post = Post.last
post.photo.url # returns your custom url instead of URL on amazonaws.com domain
=> //storage.yourcompany.com/uploads/post/1/big/1.jpg

Optimizations with jpegoptim & optipng

Using Piet, Storage can optimize your images with jpegoptim and optipng:

class PhotoStorage < Storage::Model
  include Storage::Helpers::OptimizeHelper

  # declare versions...

  def process_image(version, image)
    optimize_with_piet(image)
  end
end

Contributing

  1. Fork it ( https://github.com/[my-github-username]/storage/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request