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
121 122 123 |
# File 'lib/paperclip/storage/database.rb', line 121 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
137 138 139 140 141 142 143 144 |
# File 'lib/paperclip/storage/database.rb', line 137 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
133 134 135 |
# File 'lib/paperclip/storage/database.rb', line 133 def database_table @database_table end |
#exists?(style = default_style) ⇒ Boolean
146 147 148 149 150 151 152 |
# File 'lib/paperclip/storage/database.rb', line 146 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
183 184 185 |
# File 'lib/paperclip/storage/database.rb', line 183 def file_contents(style = default_style) file_for(style).file_contents end |
#file_for(style) ⇒ Object
177 178 179 180 181 |
# File 'lib/paperclip/storage/database.rb', line 177 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
173 174 175 |
# File 'lib/paperclip/storage/database.rb', line 173 def files instance.send("#{@paperclip_files_association_name}") end |
#flush_deletes ⇒ Object
:nodoc:
205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/paperclip/storage/database.rb', line 205 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
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/paperclip/storage/database.rb', line 187 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 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.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/paperclip/storage/database.rb', line 156 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 |