nudesign/media_magick

View on GitHub
lib/media_magick/model.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'active_support/concern'
require 'carrierwave/mongoid'
require 'media_magick/attachment_uploader'
require 'media_magick/video/parser'

module MediaMagick
  module Model
    extend ActiveSupport::Concern

    module ClassMethods
      # smell
      def attaches_many(name, options = {})
        attaches_block = block_given? ? Proc.new : nil

        name_camelcase = create_attaches_class(name, options, attaches_block) do
          if options[:allow_videos]
            raise "name 'videos' not allowed" if name.to_s == "videos"
            create_video_methods(name)
          end

          field :priority, type: Integer, default: 0

          default_scope -> { asc(:priority) }

          embedded_in(:attachmentable, polymorphic: true)
        end

        embeds_many(name, :as => :attachmentable, class_name: "#{self}#{name_camelcase}", cascade_callbacks: true)
      end

      # smell
      def attaches_one(name, options = {})
        attaches_block = block_given? ? Proc.new : nil

        name_camelcase = create_attaches_class(name, options, attaches_block) do
          if options[:allow_videos]
            raise "name 'video' not allowed" if name.to_s == "video"
            create_video_methods(name)
          end

          embedded_in(name)
        end

        embeds_one(name, class_name: "#{self}#{name_camelcase}", cascade_callbacks: true)
      end

      private

      def create_attaches_class(name, options, attaches_block, &block)
        klass = Class.new do
          include Mongoid::Document
          extend CarrierWave::Mount

          field :type, type: String, default: options[:as] || 'image'
          field :dimensions, type: Hash, default: {}

          before_destroy :cache_store_dir
          after_destroy :remove_directory

          def cache_store_dir
            @cache_store_dir = store_dir
          end

          def remove_directory
            FileUtils.remove_dir("#{Rails.root}/public/#{@cache_store_dir}", force: false)
          end

          def self.create_video_methods(name)
            field :video, type: String

            def video=(url)
              self.type = 'video'
              super

              video = MediaMagick::Video::Parser.new(url)
              send(self.class::ATTACHMENT).store!(video.to_image) if video.valid?
            end

            def source(options = {})
              video = MediaMagick::Video::Parser.new(self.video)
              video.to_html(options) if video.valid?
            end
          end

          class_eval(&block) if block_given?

          mount_uploader name.to_s.singularize, (options[:uploader] || AttachmentUploader)

          self.const_set "TYPE", options[:type] || :image
          self.const_set "ATTACHMENT", name.to_s.singularize

          class_eval(&attaches_block) if attaches_block

          def method_missing(method, args = nil)
            return self.send(self.class::ATTACHMENT).file.filename if method == :filename
            self.send(self.class::ATTACHMENT).send(method)
          end
        end

        name_camelcase = name.to_s.camelcase

        # sets klass to a constant
        # ProductImages = klass
        constantize_embedded_klass(self, name_camelcase, klass)

        return name_camelcase
      end

      def constantize_embedded_klass(klass_self, relation_name, embedded_klass)
        parent = klass_self.parents.first # module or Object
        embedded_klass_name = "#{klass_self.to_s.demodulize}#{relation_name}"
        parent.const_set embedded_klass_name, embedded_klass
      end

    end
  end
end