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, #protocol_and_host

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



267
268
269
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 267

def action_id
  model.selected_content_action_id || action_id_stand_in
end

#cache_dirObject



227
228
229
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 227

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

#create_versions?(_new_file) ⇒ Boolean

Returns:

  • (Boolean)


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

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)


190
191
192
193
194
195
196
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 190

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



174
175
176
177
178
179
180
181
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 174

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



166
167
168
169
170
171
172
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 166

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

#local_url(opts = {}) ⇒ Object



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

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

#original_filenameObject



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

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)



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

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

#public_pathObject



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

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

#retrieve_pathObject



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

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.



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

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

#tmp_pathObject



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

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



208
209
210
211
212
213
214
215
216
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 208

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

#url_filename(opts = {}) ⇒ Object



198
199
200
201
202
203
204
205
206
# File 'mod/carrierwave/lib/carrier_wave/file_card_uploader.rb', line 198

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

#valid?Boolean

Returns:

  • (Boolean)


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

def valid?
  extension.present?
end