Module: Paperclip::Storage::Database
- Defined in:
- lib/paperclip/storage.rb
Overview
Store files in a database.
Usage is identical to the file system storage version, except:
-
In your model specify the “database” storage option; for example:
has_attached_file :avatar, :storage => :database
-
The file will be stored in a column called [attachment name]_file (e.g. “avatar_file”) by default.
To specify a different column name, use :column, like this:
has_attached_file :avatar, :storage => :database, :column => 'avatar_data'
If you have defined different styles, these files will be stored in additional columns called [attachment name]_[style name]_file (e.g. “avatar_thumb_file”) by default.
To specify different column names for styles, use :column in the style definition, like this:
has_attached_file :avatar,
:storage => :database,
:styles => {
:medium => {:geometry => "300x300>", :column => 'medium_file'},
:thumb => {:geometry => "100x100>", :column => 'thumb_file'}
}
-
You need to create these new columns in your migrations or you’ll get an exception. Example:
add_column :users, :avatar_file, :binary
add_column :users, :avatar_medium_file, :binary
add_column :users, :avatar_thumb_file, :binary
Note the “binary” migration will not work for the LONGBLOB type in MySQL for the file_contents column. You may need to craft a SQL statement for your migration, depending on which database server you are using. Here’s an example migration for MySQL:
execute 'ALTER TABLE users ADD COLUMN avatar_file LONGBLOB'
execute 'ALTER TABLE users ADD COLUMN avatar_medium_file LONGBLOB'
execute 'ALTER TABLE users ADD COLUMN avatar_thumb_file LONGBLOB'
-
To avoid performance problems loading all of the BLOB columns every time you access
your ActiveRecord object, a class method is provided on your model called “select_without_file_columns_for.” This is set to a :select scope hash that will instruct ActiveRecord::Base.find to load all of the columns except the BLOB/file data columns.
If you’re using Rails 2.3, you can specify this as a default scope:
default_scope select_without_file_columns_for(:avatar)
Or if you’re using Rails 2.1 or 2.2 you can use it to create a named scope:
named_scope :without_file_data, select_without_file_columns_for(:avatar)
-
By default, URLs will be set to this pattern:
/:relative_root/:class/:attachment/:id?style=:style
Example:
/app-root-url/users/avatars/23?style=original
The idea here is that to retrieve a file from the database storage, you will need some controller’s code to be executed.
Once you pick a controller to use for downloading, you can add this line to generate the download action for the default URL/action (the plural attachment name), “avatars” in this example:
downloads_files_for :user, :avatar
Or you can write a download method manually if there are security, logging or other requirements.
If you prefer a different URL for downloading files you can specify that in the model; e.g.:
has_attached_file :avatar, :storage => :database, :url => '/users/show_avatar/:id/:style'
-
Add a route for the download to the controller which will handle downloads, if necessary.
The default URL, /:relative_root/:class/:attachment/:id?style=:style, will be matched by the default route: :controller/:action/:id
Defined Under Namespace
Modules: ControllerClassMethods
Class Method Summary collapse
Instance Method Summary collapse
- #assign(uploaded_file) ⇒ Object
- #column_for_style(style) ⇒ Object
- #exists?(style = default_style) ⇒ Boolean
- #file_contents(style = default_style) ⇒ Object (also: #data)
- #flush_deletes ⇒ Object
- #flush_writes ⇒ Object
- #instance_read_file(style) ⇒ Object
- #instance_write_file(style, value) ⇒ Object
- #path(style = default_style) ⇒ Object
- #queue_existing_for_delete ⇒ Object
-
#to_file(style = default_style) ⇒ Object
(also: #to_io)
Returns representation of the data of the file assigned to the given style, in the format most representative of the current storage.
Class Method Details
.extended(base) ⇒ Object
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/paperclip/storage.rb', line 315 def self.extended base base.instance_eval do @file_columns = @options[:file_columns] if @url == base.class.[:url] @url = ":relative_root/:class/:attachment/:id?style=:style" end end base.class.interpolations[:relative_root] = lambda do |, style| begin if ActionController::AbstractRequest.respond_to?(:relative_url_root) relative_url_root = ActionController::AbstractRequest.relative_url_root end rescue NameError end if !relative_url_root && ActionController::Base.respond_to?(:relative_url_root) relative_url_root = ActionController::Base.relative_url_root end relative_url_root end ActiveRecord::Base.logger.info("[paperclip] Database Storage Initalized.") end |
Instance Method Details
#assign(uploaded_file) ⇒ Object
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/paperclip/storage.rb', line 386 def assign uploaded_file # Assign standard metadata attributes and perform post processing as usual super # Save the file contents for all styles in ActiveRecord immediately (before save) @queued_for_write.each do |style, file| instance_write_file(style, file.read) end # If we are assigning another Paperclip attachment, then fixup the # filename and content type; necessary since Tempfile is used in to_file if uploaded_file.is_a?(Paperclip::Attachment) instance_write(:file_name, uploaded_file.instance_read(:file_name)) instance_write(:content_type, uploaded_file.instance_read(:content_type)) end end |
#column_for_style(style) ⇒ Object
337 338 339 |
# File 'lib/paperclip/storage.rb', line 337 def column_for_style style @file_columns[style.to_sym] end |
#exists?(style = default_style) ⇒ Boolean
363 364 365 |
# File 'lib/paperclip/storage.rb', line 363 def exists?(style = default_style) !file_contents(style).nil? end |
#file_contents(style = default_style) ⇒ Object Also known as: data
358 359 360 |
# File 'lib/paperclip/storage.rb', line 358 def file_contents(style = default_style) instance_read_file(style) end |
#flush_deletes ⇒ Object
418 419 420 |
# File 'lib/paperclip/storage.rb', line 418 def flush_deletes @queued_for_delete = [] end |
#flush_writes ⇒ Object
414 415 416 |
# File 'lib/paperclip/storage.rb', line 414 def flush_writes @queued_for_write = {} end |
#instance_read_file(style) ⇒ Object
341 342 343 344 345 346 347 348 349 |
# File 'lib/paperclip/storage.rb', line 341 def instance_read_file(style) column = column_for_style(style) responds = instance.respond_to?(column) cached = self.instance_variable_get("@_#{column}") return cached if cached # The blob attribute will not be present if select_without_file_columns_for was used instance.reload :select => column if !instance.attribute_present?(column) && !instance.new_record? instance.send(column) if responds end |
#instance_write_file(style, value) ⇒ Object
351 352 353 354 355 356 |
# File 'lib/paperclip/storage.rb', line 351 def instance_write_file(style, value) setter = :"#{column_for_style(style)}=" responds = instance.respond_to?(setter) self.instance_variable_set("@_#{setter.to_s.chop}", value) instance.send(setter, value) if responds end |
#path(style = default_style) ⇒ Object
382 383 384 |
# File 'lib/paperclip/storage.rb', line 382 def path style = default_style original_filename.nil? ? nil : column_for_style(style) end |
#queue_existing_for_delete ⇒ Object
404 405 406 407 408 409 410 411 412 |
# File 'lib/paperclip/storage.rb', line 404 def queue_existing_for_delete [:original, *@styles.keys].uniq.each do |style| instance_write_file(style, nil) end instance_write(:file_name, nil) instance_write(:content_type, nil) instance_write(:file_size, nil) instance_write(:updated_at, nil) end |
#to_file(style = default_style) ⇒ Object Also known as: to_io
Returns representation of the data of the file assigned to the given style, in the format most representative of the current storage.
369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/paperclip/storage.rb', line 369 def to_file style = default_style if @queued_for_write[style] @queued_for_write[style] elsif exists?(style) tempfile = Tempfile.new instance_read(:file_name) tempfile.write file_contents(style) tempfile else nil end end |