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 files will be stored in a new database table named with the plural attachment name by default, “avatars” in this example.
-
You need to create this new storage table with at least these columns:
- file_contents
- style
- the primary key for the parent model (e.g. user_id)
Note the “binary” migration will not work for the LONGBLOG type in MySQL for the file_cotents 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:
create_table :avatars do |t|
t.string :style
t.integer :user_id
t.
end execute ‘ALTER TABLE avatars ADD COLUMN file_contents LONGBLOB’
You can optionally specify any storage table name you want and whether or not deletion is done by cascading or not as follows:
has_attached_file :avatar, :storage => :database, :database_table => 'avatar_files', :cascade_deletion => true
-
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
- #copy_to_local_file(style, dest_path) ⇒ Object
- #database_path(style) ⇒ Object
- #database_table ⇒ Object
- #exists?(style = default_style) ⇒ Boolean
- #file_contents(style = default_style) ⇒ Object
- #file_for(style) ⇒ Object
- #files ⇒ Object
-
#flush_deletes ⇒ Object
:nodoc:.
- #flush_writes ⇒ 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
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/paperclip/storage/database.rb', line 59 def self.extended(base) base.instance_eval do setup_paperclip_file_model setup_paperclip_files_association base end Paperclip.interpolates(:database_path) do |, style| .database_path(style) 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) ActionController::Base.relative_url_root end end ActiveRecord::Base.logger.info("[paperclip] Database Storage Initalized.") end |
Instance Method Details
#copy_to_local_file(style, dest_path) ⇒ Object
128 129 130 |
# File 'lib/paperclip/storage/database.rb', line 128 def copy_to_local_file(style, dest_path) File.open(dest_path, 'wb+'){|df| to_file(style).tap{|sf| File.copy_stream(sf, df); sf.close;sf.unlink} } end |
#database_path(style) ⇒ Object
144 145 146 147 148 149 150 151 |
# File 'lib/paperclip/storage/database.rb', line 144 def database_path(style) paperclip_file = file_for(style) if paperclip_file "#{database_table}(id=#{paperclip_file.id},style=#{style.to_s})" else "#{database_table}(id=new,style=#{style.to_s})" end end |
#database_table ⇒ Object
140 141 142 |
# File 'lib/paperclip/storage/database.rb', line 140 def database_table @database_table end |
#exists?(style = default_style) ⇒ Boolean
153 154 155 156 157 158 159 |
# File 'lib/paperclip/storage/database.rb', line 153 def exists?(style = default_style) if original_filename instance.send("#{@paperclip_files_association_name}").where(:style => style).exists? else false end end |
#file_contents(style = default_style) ⇒ Object
190 191 192 |
# File 'lib/paperclip/storage/database.rb', line 190 def file_contents(style = default_style) file_for(style).file_contents end |
#file_for(style) ⇒ Object
184 185 186 187 188 |
# File 'lib/paperclip/storage/database.rb', line 184 def file_for(style) db_result = instance.send("#{@paperclip_files_association_name}").send(:file_for, style.to_s) raise RuntimeError, "More than one result for #{style}" if db_result.size > 1 db_result.first end |
#files ⇒ Object
180 181 182 |
# File 'lib/paperclip/storage/database.rb', line 180 def files instance.send("#{@paperclip_files_association_name}") end |
#flush_deletes ⇒ Object
:nodoc:
212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/paperclip/storage/database.rb', line 212 def flush_deletes #:nodoc: ActiveRecord::Base.logger.info("[paperclip] Deleting files for #{name}") @queued_for_delete.uniq! ##This is apparently necessary for paperclip v 3.x @queued_for_delete.each do |path| /id=([0-9]+)/.match(path) if @options[:cascade_deletion] && !instance.class.exists?(instance.id) raise RuntimeError, "Deletion has not been done by through cascading." if @paperclip_file_model.exists?($1) else @paperclip_file_model.destroy $1 end end @queued_for_delete = [] end |
#flush_writes ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/paperclip/storage/database.rb', line 194 def flush_writes ActiveRecord::Base.logger.info("[paperclip] Writing files for #{name}") @queued_for_write.each do |style, file| case ActiveModel::VERSION::MAJOR when 3 paperclip_file = instance.send(@paperclip_files_association_name).send(:find_or_create_by_style, style.to_s) when 4,5,6 paperclip_file = instance.send(@paperclip_files_association_name).send(:find_or_create_by, style: style.to_s) else raise "ActiveModel version #{ActiveModel::VERSION::STRING} is not supported (yet)" end paperclip_file.file_contents = file.read paperclip_file.save! instance.reload end @queued_for_write = {} 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.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/paperclip/storage/database.rb', line 163 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.binmode tempfile.write file_contents(style) tempfile.flush tempfile.rewind tempfile else nil end end |