Class: CarrierWave::FileCardUploader

Inherits:
Uploader::Base
  • Object
show all
Includes:
Card::Env::Location
Defined in:
mod/carrierwave/lib/carrier_wave/file_card_uploader.rb

Overview

Takes care of the file upload for cards with attached files. Most of the upload behaviour depends on the card itself. (e.g. card type and storage option chosen for the card). So in contrary to CarrierWave's default uploader we depend very much on the model (= card object) to get the correct paths for retrieving and storing the file.

Cards that support attachments (by default those are cards of type "file" and "image") accept a file handle as a card attribute.

It's possible to upload files using a url. The card attribute for that is remote__url

Storage types

You can choose between four different storage options

  • coded: These files are in the codebase, like the default logo. Every view is a wagn request.
  • local: Uploaded files which are stored in a local upload directory (upload path is configurable via config.paths["files"]). If read permissions are set such that "Anyone" can read, then there is a symlink from the public directory. Otherwise every view is a wagn request.
  • cloud: You can configure buckets that refer to an external storage service. Link is rendered as absolute url
  • web: A fixed url (to external source). No upload or other file processing. Link is just the saved url.

Currently, there is no web interface that let's a user or administrator choose a storage option for a specific card or set of cards. There is only a global config option to set the storage type for all new uploads (config.storage_type). On the *admin card it's possible to update all existing file cards according to the current global config.

Storage types for single cards can be changed by developers using the card attributes "storage_type", "bucket", and "mod".

Depending on the storage type the uploader uses the following paths and identifiers.

Identifier (stored in the database as db_content)

  • coded: :codename/mod_name.ext
  • local: ~card_id/action_id.ext
  • cloud: (bucket)/card_id/action_id.ext
  • web: http://url

Storage path

  • coded: mod_dir/file/codename/type_code(-variant).ext (no colon on codename!)
  • local: files_dir/card_id/action_id(-variant).ext (no tilde on id!)
  • cloud: bucket/bucket_subdir/id/action_id(-variant).ext
  • web: no storage

Variants are only used for images. Possible options are icon|small|medium|large|original. files_dir, bucket, and bucket_subdir can be changed via config options.

Supported url patterns

mark.ext mark/revision.ext mark/revision-variant.ext /files/mark/revision-variant.ext # <- public symlink if readable by # "Anyone"

can be one of the following options

  • ~
  • :

is the mod name if the file is coded or and action_id in any case

Examples: *logo.png ~22/33-medium.png # local :yeti_skin/standard-large.png # coded

Examples:

Attaching a file to a file card

Card.create name: "file card", type: :file,
            file: File.new(path_to_file)

Attaching a image to a image card

Card.create name: "file card", type: :image,
            image: File.new(path_to_image)

Create a file card using a remote url

Card.create name: "file_card", type: :file,
            remote_file_url: "http://a.file.in/the.web"

Updating a image card using a remote url

card.update_attributes remote_image_url: "http://a.image/somewhere.png"

Creating a hard-coded file

Card.create name: "file card", type_id: Card::FileID,
            file: File.new(path),
            storage_type: :coded, mod: "account"

Moving a file to a cloud service

# my_deck/config/application.rb:
config.file_buckets = {
  aws_bucket: {
    provider: "fog/aws",
    directory: "bucket-name",
    subdirectory: "files",
    credentials: {
       provider: 'AWS'                         # required
       aws_access_key_id: 'key'                # required
       aws_secret_access_key: 'secret-key'     # required
    public: true,
   }
}

# wagn console or rake task:
card.update_attributes storage_type: :cloud, bucket: :aws_bucket

Creating a file card with fixed external link

Card.create name: "file card", type_id: Card::FileID,
            content: "http://animals.org/cat.png"
            storage_type: :web

Card.create name: "file card", type_id: Card::FileID,
            file: "http://animals.org/cat.png"
            storage_type: :web

Direct Known Subclasses

ImageCardUploader

Constant Summary collapse

STORAGE_TYPES =
[:cloud, :web, :coded, :local].freeze
CONFIG_OPTIONS =
[:provider, :attributes, :directory, :public, :credentials,
:authenticated_url_expiration, :use_ssl_for_aws].freeze
CONFIG_CREDENTIAL_OPTIONS =
[
  :provider,
  :aws_access_key_id, :aws_secret_access_key, :region, :host, :endpoint,
  :google_access_key_id, :google_secret_access_key
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Card::Env::Location

#card_path, #card_url, #page_path

Instance Attribute Details

#modObject

Returns the value of attribute mod.



149
150
151
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 149

def mod
  @mod
end

Instance Method Details

#action_idObject



263
264
265
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 263

def action_id
  model.selected_content_action_id
end

#cache_dirObject



223
224
225
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 223

def cache_dir
  @model.files_base_dir + "/cache"
end

#create_versions?(_new_file) ⇒ Boolean

Returns:

  • (Boolean)


249
250
251
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 249

def create_versions? _new_file
  model.create_versions?
end

#db_content(opts = {}) ⇒ Object

generate identifier that gets stored in the card's db_content field

Parameters:

  • opts (Hash) (defaults to: {})

    generate an identifier using the given storage options instead of the storage options derived from the model and the global configuration

Options Hash (opts):

  • storage_type (Symbol)
  • mod (String)
  • bucket (Symbol)


186
187
188
189
190
191
192
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 186

def db_content opts={}
  model.with_storage_options opts do
    return model.content if model.web?
    return "" unless file.present?
    "%s/%s" % [file_dir, url_filename]
  end
end

#extensionObject



170
171
172
173
174
175
176
177
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 170

def extension
  case
  when file && file.extension.present? then ".#{file.extension}"
  when card_content = model.content    then File.extname(card_content)
  when orig = original_filename        then File.extname(orig)
  else                                   ""
  end.downcase
end

#filenameObject



162
163
164
165
166
167
168
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 162

def filename
  if model.coded?
    "#{model.type_code}#{extension}"
  else
    "#{action_id}#{extension}"
  end
end

#local_url(opts = {}) ⇒ Object



214
215
216
217
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 214

def local_url opts={}
  "%s/%s/%s" % [card_path(Card.config.files_web_path), file_dir,
                full_filename(url_filename(opts))]
end

#original_filenameObject



258
259
260
261
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 258

def original_filename
  @original_filename ||= model.selected_action &&
                         model.selected_action.comment
end

#path(version = nil) ⇒ Object

paperclip compatibility used in type/file.rb#core (base format)



254
255
256
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 254

def path version=nil
  version ? versions[version].path : super()
end

#public_pathObject



219
220
221
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 219

def public_path
  File.join Cardio.paths["public"].existent.first, url
end

#retrieve_pathObject



240
241
242
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 240

def retrieve_path
  File.join([retrieve_dir, full_filename(filename)].compact)
end

#store_path(for_file = nil) ⇒ Object

Carrierwave calls store_path without argument when it stores the file and with the identifier from the db when it retrieves the file. In our case the first part of our identifier is not part of the path but we can construct the filename from db data. So we don't need the identifier.



232
233
234
235
236
237
238
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 232

def store_path for_file=nil
  if for_file
    retrieve_path
  else
    File.join([store_dir, full_filename(filename)].compact)
  end
end

#tmp_pathObject



244
245
246
247
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 244

def tmp_path
  Dir.mkdir model.tmp_upload_dir unless Dir.exist? model.tmp_upload_dir
  File.join model.tmp_upload_dir, filename
end

#url(opts = {}) ⇒ Object



204
205
206
207
208
209
210
211
212
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 204

def url opts={}
  if model.cloud?
    file.url
  elsif model.web?
    model.content
  else
    local_url opts
  end
end

#url_filename(opts = {}) ⇒ Object



194
195
196
197
198
199
200
201
202
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 194

def url_filename opts={}
  model.with_storage_options opts do
    if model.coded?
      "#{model.mod}#{extension}"
    else
      "#{action_id}#{extension}"
    end
  end
end