module Pageflow module ReusableFile extend ActiveSupport::Concern included do belongs_to :uploader, class_name: 'User', optional: true belongs_to :entry, optional: true belongs_to :parent_file, polymorphic: true, foreign_type: :parent_file_model_type, optional: true has_many :usages, :as => :file, :class_name => 'Pageflow::FileUsage', :dependent => :destroy has_many :using_revisions, :through => :usages, :source => :revision has_many :using_entries, :through => :using_revisions, :source => :entry has_many :using_accounts, :through => :using_entries, :source => :account validate :parent_allows_type_for_nesting, :parent_belongs_to_same_entry end def parent_allows_type_for_nesting if parent_file.present? parent_class = parent_file.class file_type_of_parent = Pageflow.config.file_types.find_by_model!(parent_class) models_of_nested_file_types = file_type_of_parent.nested_file_types.map(&:model) unless models_of_nested_file_types.include?(self.class) errors[:base] << 'File type of provided parent file does not permit nesting files of '\ "type #{self.class.name}" end end end def parent_belongs_to_same_entry if parent_file.present? unless parent_file.using_entries.include?(entry) errors[:base] << 'Parent file does not belong to same entry as nested file' end end end def nested_files(model) model_table_name = model.table_name model .select("#{model_table_name}.*") .where("#{model_table_name}.parent_file_id = #{id} AND "\ "#{model_table_name}.parent_file_model_type = '#{self.class.name}'") end def file_type Pageflow.config.file_types.find_by_model!(self.class) end def cache_key # Ensure the cache key changes when the state changes. There are # cases during processing where the state is updated multiple # times in a single second. Since `cache_key` relies on # `updated_at`, which only is acurate to the second, we need to # prevent caching outdated information. "#{super}-#{state}" end # The following are method defaults for file types that do not require processing/encoding. # They are overwritten with default values in UploadableFile for files that are uploaded # through the editor. # Overwritten if a file type provides a default url for its file. def url '' end # Overwritten in case of a file type providing its original (unprocessed) file # for download in the editor. # Defaults to the default url of the file (see above) def original_url url end # Overwritten with the basename of the file. def basename 'unused' end # Overwritten in UploadableFile with attachment filename. def file_name 'unused' end # Overwritten with the list of attachments of the file type # that should get included in export archives. def attachments_for_export [] end # Overwritten in UploadableFile based on initial state_machine-state. # Defaults to false for files that only use the ReusableFile module def can_upload? false end # Overwritten with the conditions that need to be fulfilled in order to `retry` # whatever the file does (i.e. processing/transcoding). def retryable? raise 'Not implemented!' end # Overwritten with the conditions that need to be fulfilled in order to (re)use the file. def ready? raise 'Not implemented!' end # Overwritten with the conditions that indicate failure during processing. def failed? raise 'Not implemented!' end # If the conditions in retryable? are met then this method specifies what should happen when # a retry is requested, depending on the including class' processing state machine. def retry! raise 'Not implemented!' end # Gets called to trigger the `file_uploaded` event in the upload state machine of UploadableFile. # Files that are not uploaded through the editor (and therefore not using the # upload state machine of UploadableFile) can overwrite this method to trigger whatever # the file does (i.e. processing/transcoding), depending on the including class' # processing state machine. def publish! raise 'Not implemented!' end end end