Module: Dis::Model

Extended by:
ActiveSupport::Concern
Defined in:
lib/dis/model.rb,
lib/dis/model/data.rb,
lib/dis/model/class_methods.rb

Overview

Dis Model

ActiveModel extension for the model holding your data. To use it, include the module in your model:

class Document < ActiveRecord::Base
  include Dis::Model
end

You’ll need to define a few attributes in your database table. Here’s a minimal migration:

create_table :documents do |t|
  t.string  :content_hash
  t.string  :content_type
  t.integer :content_length
  t.string  :filename
end

You can override the names of any of these by setting dis_attributes.

class Document < ActiveRecord::Base
  include Dis::Model
  self.dis_attributes = {
    filename:       :my_filename,
    content_length: :filesize
  }
end

Usage

To save a file, assign to the file attribute.

document = Document.create(file: params.permit(:file))

content_type and filename will automatically be set if the supplied object quacks like a file. content_length and content_hash will always be set.

To store a binary blob without filenames or content types, set the data attribute directly.

my_data = File.read('document.pdf')
document.update(data: my_data)

The data won’t be stored until the record is saved, and only if the record is valid.

To retrieve your data, read the data attribute. The file will be lazily loaded from the store on demand and cached in memory as long as the record stays in scope.

my_data = document.data

Destroying a record will delete the file from the store, unless another record also refers to the same hash. Similarly, stale files will be purged when content changes.

Validations

No validation is performed by default. If you want to ensure that data is present, use the validates_data_presence method.

class Document < ActiveRecord::Base
  include Dis::Model
  validates_data_presence
end

If you want to validate content types, size or similar, use standard Rails validations on the metadata attributes:

validates :content_type, presence: true, format: /\Aapplication\/pdf\z/
validates :filename, presence: true, format: /\A[\w_\-\.]+\.pdf\z/i
validates :content_length, numericality: { less_than: 5.megabytes }

Defined Under Namespace

Modules: ClassMethods Classes: Data

Instance Method Summary collapse

Instance Method Details

#dataString?

Returns the data as a binary string, or nil if no data has been set.

Returns:

  • (String, nil)


96
97
98
# File 'lib/dis/model.rb', line 96

def data
  dis_data.read
end

#data=(raw_data) ⇒ void

This method returns an undefined value.

Assigns new data. This also sets content_length and content_hash.

Parameters:

  • raw_data (File, IO, String, nil)

    the content to store



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/dis/model.rb', line 112

def data=(raw_data)
  new_data = Dis::Model::Data.new(self, raw_data)
  attribute_will_change!("data") unless new_data == dis_data
  @dis_data = new_data
  dis_set :content_hash, if raw_data.nil?
                           nil
                         else
                           Storage.file_digest(new_data.read)
                         end
  dis_set :content_length, dis_data.content_length
end

#data?Boolean

Returns true if data is set.

Returns:

  • (Boolean)


103
104
105
# File 'lib/dis/model.rb', line 103

def data?
  dis_data.any?
end

#data_changed?Boolean

Returns true if the data has been changed since the object was last saved.

Returns:

  • (Boolean)


128
129
130
# File 'lib/dis/model.rb', line 128

def data_changed?
  changes.include?("data")
end

#data_file_pathString

Returns a file path to the data, preferring local storage paths. Falls back to a tempfile path if no local layer has the file.

Returns:

  • (String)


159
160
161
# File 'lib/dis/model.rb', line 159

def data_file_path
  dis_data.file_path
end

#dis_stored?Boolean

Returns true if the record has been persisted and its data has not been changed since the last save.

Returns:

  • (Boolean)


136
137
138
# File 'lib/dis/model.rb', line 136

def dis_stored?
  !(new_record? || data_changed?)
end

#file=(file) ⇒ void

This method returns an undefined value.

Assigns new data from an uploaded file. In addition to the actions performed by #data=, this will set content_type and filename.

Parameters:

  • file (ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile)

    an uploaded file that responds to content_type and original_filename



148
149
150
151
152
# File 'lib/dis/model.rb', line 148

def file=(file)
  self.data = file
  dis_set :content_type, file.content_type
  dis_set :filename, file.original_filename
end

#tempfileTempfile

Returns the data as a temporary file.

Returns:

  • (Tempfile)


166
# File 'lib/dis/model.rb', line 166

delegate :tempfile, to: :dis_data