Skip to content

Commit

Permalink
Approach to save all metadata in single column
Browse files Browse the repository at this point in the history
  • Loading branch information
gzigzigzeo committed Aug 4, 2013
1 parent 83c7ddb commit 2d9d1a5
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 31 deletions.
54 changes: 43 additions & 11 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ Add the following line to your Gemfile:
include CarrierWave::RMagick
include CarrierWave::Meta

storage :file

process :store_meta => [{md5sum: true}]

version :version do
process :resize_to_fill => [200, 200]
process :store_meta
Expand All @@ -44,21 +41,24 @@ Add the following line to your Gemfile:

= Saving values to database

Simply create database columns to hold metadata in your model's table. Currently gem supports width, height,
image_size ([width, height]), content_type, file_size and MD5 fields. Versions are supported too.
Simply create database columns to hold metadata in your model's table. Currently
gem supports width, height, image_size ([width, height]), content_type,
file_size and MD5 fields. Versions are supported too.

class TestModel
attr_accessor :image_width
attr_accessor :image_height
attr_accessor :image_image_size
attr_accessor :image_content_type
attr_accessor :image_file_size
attr_accessor :image_md5sum

attr_accessor :image_version_width
attr_accessor :image_version_height
attr_accessor :image_version_image_size
attr_accessor :image_version_content_type
attr_accessor :image_version_file_size
attr_accessor :image_version_md5sum
end

file = File.open('test.jpg')
Expand All @@ -73,19 +73,49 @@ image_size ([width, height]), content_type, file_size and MD5 fields. Versions a

When columns are available in the model instance, metadata is stored in that columns.

= Saving values in the single column

For now, works only for ActiveRecord.

```ruby
class TestModel < ActiveRecord::Base
extend CarrierWave::Meta::ActiveRecord

mount_uploader :image, TestUploader
serialize :image_meta, OpenStruct
carrierwave_meta_composed :image_meta,
:image, image_version: [:width, :height, :md5sum]
end

model = TestModel.new
model.image.store!('test.jpg')
model.image_width # 200
model.image_version_width # 200
model.image_meta # {image_width: 200, image_height: 200, ...}
```

All you need is image_meta column, all other attributes are virtual. Note
that carrierwave_meta_composed should be called after mounting uploader.

= Behind the scenes

After the file is retrieved from store or cache metadata is recalculated unless uploader has attached
model instance. If uploader has attached model instance values are read from that instance.
After the file is retrieved from store or cache metadata is recalculated
unless uploader has attached model instance. If uploader has attached
model instance values are read from that instance.

uploader = TestUploader.new
uploader.retrieve_from_store!('test.jpg')

uploader.version.width # 200

model = TestModel.new
model.image.store!('test.jpg')
model.image_width # 200
model.image.width # 200, actually read from image_width

= model_delegate_attribute

Used to synchronize data between uploader and mounted model instance. Model's instance is used like value cache.
Is used to synchronize data between uploader and mounted model instance.
Model's instance is used like value cache.

class DelegateTestModel
attr_accessor :processed
Expand Down Expand Up @@ -128,8 +158,10 @@ Used to synchronize data between uploader and mounted model instance. Model's in

When model is mounted to uploader:

1. If attribute is assigned inside uploader then corresponding property in model is also assigned.
2. If attribute is retrieved from uploader instance first checks that value is defined in model and returns it. Otherwise returns uploader's instance variable.
1. If attribute is assigned inside uploader then corresponding property
in model is also assigned.
2. If attribute is retrieved from uploader, uploader checks that value is
defined in model and returns it. Otherwise returns uploader's instance variable.
3. If file is deleted, value becomes nil.

Otherwise acts as regular uploader's instance variables.
Expand Down
1 change: 1 addition & 0 deletions carrierwave-meta.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ Gem::Specification.new do |s|
s.add_development_dependency(%q<carrierwave-vips>)
s.add_development_dependency(%q<fog>, '~> 1.3.1')
s.add_development_dependency(%q<simplecov>)
s.add_development_dependency(%q<activerecord>, '>= 3.0')
end
1 change: 1 addition & 0 deletions lib/carrierwave-meta.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
require 'carrierwave-meta/version'
require 'carrierwave-meta/model_delegate_attribute'
require 'carrierwave-meta/meta'
require 'carrierwave-meta/active_record'
22 changes: 22 additions & 0 deletions lib/carrierwave-meta/active_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module CarrierWave
module Meta
module ActiveRecord
ALLOWED = %w(width height md5sum image_size file_size content_type)

def carrierwave_meta_composed(single_attribute, *args)
defined_attrs = args.map do |arg|
name, to_define = if arg.is_a?(Symbol)
[arg, ALLOWED]
elsif arg.is_a?(Hash)
[arg.keys.first, arg.values.first]
end

to_define.map do |attr|
delegate :"#{name}_#{attr}", to: single_attribute, allow_nil: true
delegate :"#{name}_#{attr}=", to: single_attribute, allow_nil: true
end
end
end
end
end
end
31 changes: 31 additions & 0 deletions spec/modules/active_record_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'spec_helper'

describe CarrierWave::Meta::ActiveRecord do
let(:model) { TestComposedModel.new }
let(:model_with_image) do
model.tap do |m|
m.image = File.open('spec/fixtures/big.jpg')
m.save!
end
end

it "model's virtual meta attributes must exists" do
subject::ALLOWED.each do |name|
model.should respond_to(:"image_#{name}")
end
end

it "must assign model's virtual attributes and save meta column" do
subject::ALLOWED.each do |name|
model_with_image.send(:"image_#{name}").should_not be_blank
end

model_with_image.image_version_width.should_not be_blank
model_with_image.image_version_height.should_not be_blank

model_with_image.reload

model_with_image.image_version_width.should_not be_blank
model_with_image.image_version_height.should_not be_blank
end
end
12 changes: 4 additions & 8 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
require 'simplecov'
require 'mime/types'
require 'carrierwave'
require 'carrierwave/orm/activerecord'
require 'support/remote'
require 'support/current_processor'
require 'active_record'
require 'support/schema'

SimpleCov.start

Expand All @@ -24,16 +27,9 @@
require 'support/test_blank_uploader'
require 'support/test_uploader'
require 'support/test_model'
require 'support/test_composed_model'
require 'fog'

=begin
class CarrierWave::Storage::Fog::File
def original_filename
::File.basename(path)
end
end
=end

RSpec.configure do |config|
config.before do
FileUtils.rm_rf('tmp')
Expand Down
19 changes: 7 additions & 12 deletions spec/support/schema.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
ActiveRecord::Schema.define :version => 0 do
create_table "test_models", :force => true do |t|
t.string :image

t.integer :image_width
t.integer :image_height
t.string :image_content_type
t.integer :image_file_size
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")

ActiveRecord::Schema.define :version => 1 do

t.integer :image_version_width
t.integer :image_version_height
t.integer :image_version_file_size
t.string :image_version_content_type
create_table "test_composed_models", :force => true do |t|
t.string :image
t.text :image_meta
end

end
7 changes: 7 additions & 0 deletions spec/support/test_composed_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class TestComposedModel < ActiveRecord::Base
extend CarrierWave::Meta::ActiveRecord

mount_uploader :image, TestUploader
serialize :image_meta, OpenStruct
carrierwave_meta_composed :image_meta, :image, image_version: [:width, :height]
end

0 comments on commit 2d9d1a5

Please sign in to comment.