Skip to content

Commit

Permalink
First stab at supporting arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas Nicklas and Lisa Hammarström committed Oct 17, 2014
1 parent 1f168cd commit e38789c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 60 deletions.
26 changes: 14 additions & 12 deletions lib/carrierwave/mount_multiple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,35 +156,35 @@ def #{column}=(new_file); super; end
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
def #{column}
_mounter(:#{column}).uploader
_mounter(:#{column}).uploaders
end
def #{column}=(new_file)
_mounter(:#{column}).cache(new_file)
def #{column}=(new_files)
_mounter(:#{column}).cache(new_files)
end
def #{column}?
_mounter(:#{column}).present?
end
def #{column}_url(*args)
_mounter(:#{column}).url(*args)
_mounter(:#{column}).urls(*args)
end
def #{column}_cache
_mounter(:#{column}).cache_name
_mounter(:#{column}).cache_names
end
def #{column}_cache=(cache_name)
_mounter(:#{column}).cache_name = cache_name
_mounter(:#{column}).cache_names = cache_name
end
def remote_#{column}_url
_mounter(:#{column}).remote_url
_mounter(:#{column}).remote_urls
end
def remote_#{column}_url=(url)
_mounter(:#{column}).remote_url = url
def remote_#{column}_url=(urls)
_mounter(:#{column}).remote_urls = urls
end
def remove_#{column}
Expand Down Expand Up @@ -220,11 +220,13 @@ def #{column}_download_error
end
def write_#{column}_identifier
_mounter(:#{column}).write_identifier
column = _mounter(:#{column}).serialization_column
value = _mounter(:#{column}).write_identifiers
write_uploader(column, value)
end
def #{column}_identifier
_mounter(:#{column}).identifier
def #{column}_identifiers
_mounter(:#{column}).identifiers
end
def store_previous_model_for_#{column}
Expand Down
67 changes: 40 additions & 27 deletions lib/carrierwave/mounter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module CarrierWave
# this is an internal class, used by CarrierWave::Mount so that
# we don't pollute the model with a lot of methods.
class Mounter #:nodoc:
attr_reader :column, :record, :remote_url, :integrity_error, :processing_error, :download_error
attr_reader :column, :record, :remote_urls, :integrity_error, :processing_error, :download_error
attr_accessor :remove

def initialize(record, column, options={})
Expand All @@ -16,25 +16,31 @@ def write_identifier
return if record.frozen?

if remove?
record.write_uploader(serialization_column, nil)
nil
elsif uploader.identifier.present?
record.write_uploader(serialization_column, uploader.identifier)
uploaders.map(&:identifier)
end
end

def identifier
record.read_uploader(serialization_column)
def identifiers
[record.read_uploader(serialization_column)].flatten.reject(&:blank?)
end

def uploader
@uploader ||= record.class.uploaders[column].new(record, column)
@uploader.retrieve_from_store!(identifier) if @uploader.blank? && identifier.present?

@uploader
def uploaders
@uploaders ||= identifiers.map do |identifier|
uploader = record.class.uploaders[column].new(record, column)
uploader.retrieve_from_store!(identifier) if identifier.present?
uploader
end
end

def cache(new_file)
uploader.cache!(new_file)
def cache(new_files)
@uploaders = new_files.map do |new_file|
uploader = record.class.uploaders[column].new(record, column)
uploader.cache!(new_file)
uploader
end

@integrity_error = nil
@processing_error = nil
rescue CarrierWave::IntegrityError => e
Expand All @@ -45,23 +51,32 @@ def cache(new_file)
raise e unless option(:ignore_processing_errors)
end

def cache_name
uploader.cache_name
def cache_names
uploader.map(&:cache_names)
end

def cache_name=(cache_name)
uploader.retrieve_from_cache!(cache_name) unless uploader.cached?
def cache_names=(cache_names)
# unless uploader.cached?
@uploaders = cache_names.map do |cache_name|
uploader = record.class.uploaders[column].new(record, column)
uploader.retrieve_from_cache!(cache_name)
uploader
end
rescue CarrierWave::InvalidParameter
end

def remote_url=(url)
def remote_urls=(urls)
return if url.blank?

@remote_url = url
@remote_urls = urls
@download_error = nil
@integrity_error = nil

uploader.download!(url)
@uploaders = urls.map do |url|
uploader = record.class.uploaders[column].new(record, column)
uploader.download!(url)
uploader
end

rescue CarrierWave::DownloadError => e
@download_error = e
Expand All @@ -75,29 +90,27 @@ def remote_url=(url)
end

def store!
return if uploader.blank?

if remove?
uploader.remove!
remove!
else
uploader.store!
uploaders.reject(&:blank?).each(&:store!)
end
end

def url(*args)
uploader.url(*args)
def urls(*args)
uploaders.map { |u| u.url(*args) }
end

def blank?
uploader.blank?
uploaders.empty?
end

def remove?
remove.present? && remove !~ /\A0|false$\z/
end

def remove!
uploader.remove!
uploaders.reject(&:blank?).each(&:remove!)
end

def serialization_column
Expand Down
50 changes: 29 additions & 21 deletions spec/mount_multiple_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@ def images=(val)
end
end

@instance.images = stub_file('test.jpg')
@instance.images.should be_an_instance_of(@uploader)
@instance.images = [stub_file('test.jpg')]
@instance.images[0].should be_an_instance_of(@uploader)
end

it "should inherit uploaders to subclasses" do
@subclass = Class.new(@class)
@subclass_instance = @subclass.new
@subclass_instance.images = stub_file('test.jpg')
@subclass_instance.images.should be_an_instance_of(@uploader)
@subclass_instance.images = [stub_file('test.jpg'), stub_file('new.jpeg')]
@subclass_instance.images[0].should be_an_instance_of(@uploader)
@subclass_instance.images[1].should be_an_instance_of(@uploader)
end

it "should allow marshalling uploaders and versions" do
Expand All @@ -52,15 +53,17 @@ def rotate
@uploader.version :thumb do
process :rotate
end
@instance.images = stub_file('test.jpg')
@instance.images = [stub_file('test.jpg')]
lambda { Marshal.dump @instance.images }.should_not raise_error
end

describe "expected behavior with subclassed uploaders" do
before do
@class = Class.new
@class.send(:extend, CarrierWave::MountMultiple)
@uploader1 = Class.new(CarrierWave::Uploader::Base)
@uploader1 = Class.new(CarrierWave::Uploader::Base) do
[:rotate, :compress, :encrypt, :shrink].each { |m| define_method(m) {} }
end
@uploader1.process :rotate
@uploader1.version :thumb do
process :compress
Expand All @@ -73,16 +76,18 @@ def rotate
@class.mount_uploaders(:images1, @uploader1)
@class.mount_uploaders(:images2, @uploader2)
@instance = @class.new
@instance.images1 = [stub_file('test.jpg')]
@instance.images2 = [stub_file('test.jpg')]
end

it "should inherit defined versions" do
@instance.images1.should respond_to(:thumb)
@instance.images2.should respond_to(:thumb)
@instance.images1[0].should respond_to(:thumb)
@instance.images2[0].should respond_to(:thumb)
end

it "should not inherit versions defined in subclasses" do
@instance.images1.should_not respond_to(:secret)
@instance.images2.should respond_to(:secret)
@instance.images1[0].should_not respond_to(:secret)
@instance.images2[0].should respond_to(:secret)
end

it "should inherit defined processors properly" do
Expand All @@ -96,29 +101,32 @@ def rotate

describe '#images' do

it "should return a blank uploader when nothing has been assigned" do
@instance.should_receive(:read_uploader).with(:images).twice.and_return(nil)
@instance.images.should be_an_instance_of(@uploader)
@instance.images.should be_blank
it "should return an empty array when nothing has been assigned" do
@instance.should_receive(:read_uploader).with(:images).and_return(nil)
@instance.images.should eq []
end

it "should return a blank uploader when an empty string has been assigned" do
@instance.should_receive(:read_uploader).with(:images).twice.and_return('')
@instance.images.should be_an_instance_of(@uploader)
@instance.images.should be_blank
it "should return an empty array when an empty string has been assigned" do
@instance.should_receive(:read_uploader).with(:images).and_return('')
@instance.images.should eq []
end

it "should retrieve a file from the storage if a value is stored in the database" do
@instance.should_receive(:read_uploader).with(:images).at_least(:once).and_return('test.jpg')
@instance.images.should be_an_instance_of(@uploader)
@instance.should_receive(:read_uploader).with(:images).at_least(:once).and_return(['test.jpg', 'new.jpeg'])
@instance.images[0].should be_an_instance_of(@uploader)
@instance.images[1].should be_an_instance_of(@uploader)
end

it "should set the path to the store dir" do
@instance.should_receive(:read_uploader).with(:images).at_least(:once).and_return('test.jpg')
@instance.images.current_path.should == public_path('uploads/test.jpg')
@instance.images[0].current_path.should == public_path('uploads/test.jpg')
end

end
end
end

__END__

describe '#images=' do

Expand Down

0 comments on commit e38789c

Please sign in to comment.