Module: Paperclip::Storage::Database
- Defined in:
- lib/paperclip/storage/database.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
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/paperclip/storage/database.rb', line 76 def self.extended base base.instance_eval do @file_columns = @options[:file_columns] if @url == base.class.[:url] @url = "/:class/:attachment/:id?style=:style" end end Paperclip.interpolates(:relative_root) 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
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/paperclip/storage/database.rb', line 148 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| file.rewind 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
98 99 100 |
# File 'lib/paperclip/storage/database.rb', line 98 def column_for_style style @file_columns[style.to_sym] end |
#exists?(style = default_style) ⇒ Boolean
124 125 126 |
# File 'lib/paperclip/storage/database.rb', line 124 def exists?(style = default_style) !file_contents(style).nil? end |
#file_contents(style = default_style) ⇒ Object Also known as: data
119 120 121 |
# File 'lib/paperclip/storage/database.rb', line 119 def file_contents(style = default_style) instance_read_file(style) end |
#flush_deletes ⇒ Object
181 182 183 |
# File 'lib/paperclip/storage/database.rb', line 181 def flush_deletes @queued_for_delete = [] end |
#flush_writes ⇒ Object
177 178 179 |
# File 'lib/paperclip/storage/database.rb', line 177 def flush_writes @queued_for_write = {} end |
#instance_read_file(style) ⇒ Object
102 103 104 105 106 107 108 109 110 |
# File 'lib/paperclip/storage/database.rb', line 102 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
112 113 114 115 116 117 |
# File 'lib/paperclip/storage/database.rb', line 112 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
144 145 146 |
# File 'lib/paperclip/storage/database.rb', line 144 def path style = default_style original_filename.nil? ? nil : column_for_style(style) end |
#queue_existing_for_delete ⇒ Object
167 168 169 170 171 172 173 174 175 |
# File 'lib/paperclip/storage/database.rb', line 167 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.
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/paperclip/storage/database.rb', line 130 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 |