Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom Paperclip mappings #1271

Merged
merged 1 commit into from Nov 26, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 29 additions & 19 deletions lib/carrierwave/compatibility/paperclip.rb
Expand Up @@ -46,11 +46,31 @@ module Compatibility
# THE SOFTWARE.
#
module Paperclip
extend ActiveSupport::Concern

DEFAULT_MAPPINGS = {
:rails_root => lambda{|u, f| Rails.root.to_s },
:rails_env => lambda{|u, f| Rails.env },
:id_partition => lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")},
:id => lambda{|u, f| u.model.id },
:attachment => lambda{|u, f| u.mounted_as.to_s.downcase.pluralize },
:style => lambda{|u, f| u.paperclip_style },
:basename => lambda{|u, f| u.filename.gsub(/#{File.extname(u.filename)}$/, "") },
:extension => lambda{|u, d| File.extname(u.filename).gsub(/^\.+/, "")},
:class => lambda{|u, f| u.model.class.name.underscore.pluralize}
}

included do
attr_accessor :filename
class_attribute :mappings
self.mappings ||= DEFAULT_MAPPINGS.dup
end

def store_path(for_file=filename)
path = paperclip_path
self.filename = for_file
path ||= File.join(*[store_dir, paperclip_style.to_s, for_file].compact)
interpolate_paperclip_path(path, for_file)
interpolate_paperclip_path(path)
end

def store_dir
Expand All @@ -68,28 +88,18 @@ def paperclip_style
version_name || paperclip_default_style
end

private

def interpolate_paperclip_path(path, filename)
mappings.inject(path) do |agg, pair|
agg.gsub(":#{pair[0]}") { pair[1].call(self, filename).to_s }
module ClassMethods
def interpolate(sym, &block)
mappings[sym] = block
end
end

def mappings
[
[:rails_root , lambda{|u, f| Rails.root }],
[:rails_env , lambda{|u, f| Rails.env }],
[:class , lambda{|u, f| u.model.class.name.underscore.pluralize}],
[:id_partition , lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")}],
[:id , lambda{|u, f| u.model.id }],
[:attachment , lambda{|u, f| u.mounted_as.to_s.downcase.pluralize }],
[:style , lambda{|u, f| u.paperclip_style }],
[:basename , lambda{|u, f| f.gsub(/#{File.extname(f)}$/, "") }],
[:extension , lambda{|u, f| File.extname(f).gsub(/^\.+/, "")}]
]
private
def interpolate_paperclip_path(path)
mappings.each_pair.inject(path) do |agg, pair|
agg.gsub(":#{pair[0]}") { pair[1].call(self, self.paperclip_style).to_s }
end
end

end # Paperclip
end # Compatibility
end # CarrierWave
88 changes: 88 additions & 0 deletions spec/compatibility/paperclip_spec.rb
Expand Up @@ -13,9 +13,17 @@ module Rails; end unless defined?(Rails)
Rails.stub(:env).and_return('test')
@uploader_class = Class.new(CarrierWave::Uploader::Base) do
include CarrierWave::Compatibility::Paperclip

version :thumb
version :list

end

@model = mock('a model')
@model.stub!(:id).and_return(23)
@model.stub!(:ook).and_return('eek')
@model.stub!(:money).and_return('monkey.png')

@uploader = @uploader_class.new(@model, :monkey)
end

Expand Down Expand Up @@ -47,6 +55,86 @@ module Rails; end unless defined?(Rails)
@uploader.stub!(:paperclip_path).and_return("/foo/:id_partition/bar")
@uploader.store_path("monkey.png").should == "/foo/000/000/023/bar"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Ruby 1.8 doesn't have ordered hashes, this particular spec example occasionally fails on 1.8.7. That's because sometimes the mapping for :id is used instead of the mapping for id_partition, causing the #store_path to return "/foo/23_partition/bar". Whoops.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

it "should interpolate the basename" do
@uploader.stub!(:paperclip_path).and_return("/foo/:basename/bar")
@uploader.store_path("monkey.png").should == "/foo/monkey/bar"
end

it "should interpolate the extension" do
@uploader.stub!(:paperclip_path).and_return("/foo/:extension/bar")
@uploader.store_path("monkey.png").should == "/foo/png/bar"
end

end

describe '.interpolate' do
before do
@uploader_class.interpolate :ook do |custom, style|
custom.model.ook
end


@uploader_class.interpolate :aak do |model, style|
style
end
end

it 'should allow you to add custom interpolations' do
@uploader.stub!(:paperclip_path).and_return("/foo/:id/:ook")
@uploader.store_path("monkey.png").should == '/foo/23/eek'
end

it 'mimics paperclips arguments' do
@uploader.stub!(:paperclip_path).and_return("/foo/:aak")
@uploader.store_path("monkey.png").should == '/foo/original'
end

context 'when multiple uploaders include the compatibility module' do
before do
@uploader_class_other = Class.new(CarrierWave::Uploader::Base) do
include CarrierWave::Compatibility::Paperclip

version :thumb
version :list
end

@uploader = @uploader_class_other.new(@model, :monkey)
end

it 'should not share custom interpolations' do
@uploader.stub!(:paperclip_path).and_return("/foo/:id/:ook")
@uploader.store_path('monkey.jpg').should == '/foo/23/:ook'
end

end

context 'when there are multiple versions' do
before do
@complex_uploader_class = Class.new(CarrierWave::Uploader::Base) do
include CarrierWave::Compatibility::Paperclip

interpolate :ook do |model, style|
'eek'
end

version :thumb
version :list

def paperclip_path
"#{public_path}/foo/:ook/:id/:style"
end
end

@uploader = @complex_uploader_class.new(@model, :monkey)
end

it 'should interpolate for all versions correctly' do
@file = File.open(file_path('test.jpg'))
@uploader.store!(@file)
@uploader.thumb.path.should == "#{public_path}/foo/eek/23/thumb"
@uploader.list.path.should == "#{public_path}/foo/eek/23/list"
end
end
end
end