module Uploader module Fileuploads def self.included(base) base.send :extend, SingletonMethods end module SingletonMethods # Join ActiveRecord object with uploaded file # Usage: # # class Article < ActiveRecord::Base # has_one :picture, :as => :assetable, :dependent => :destroy # # fileuploads :picture # end # # def fileuploads(*args) options = args.extract_options! class_attribute :fileuploads_options, :instance_writer => false self.fileuploads_options = options class_attribute :fileuploads_columns, :instance_writer => false self.fileuploads_columns = args.map(&:to_sym) unless self.is_a?(ClassMethods) include InstanceMethods extend ClassMethods after_save :fileuploads_update, :if => :fileupload_changed? fileuploads_columns.each { |asset| accepts_nested_attributes_for asset, :allow_destroy => true } end end end module ClassMethods # Update reflection klass by guid def fileupload_update(record_id, guid, method) query = fileupload_klass(method).where(:guid => guid, :assetable_type => base_class.name.to_s) query.update_all(:assetable_id => record_id, :guid => nil) end # Find asset by guid def fileupload_find(method, guid) klass = fileupload_klass(method) klass.where(:guid => guid).first end # Find class by reflection def fileupload_klass(method) reflect_on_association(method.to_sym).klass end unless respond_to?(:base_class) def base_class self end end end module InstanceMethods # Generate unique key def fileupload_guid @fileupload_guid ||= Uploader.guid end def fileupload_guid=(value) @fileupload_changed = true unless value.blank? @fileupload_guid = value.blank? ? nil : value end def fileupload_changed? @fileupload_changed === true end def fileupload_multiple?(method) association = self.class.reflect_on_association(method.to_sym) if association.respond_to?(:collection?) !!(association && association.collection?) else association.macro == :has_many end end # Find or build new asset object def fileupload_asset(method) if fileuploads_columns.include?(method.to_sym) asset = new_record? ? self.class.fileupload_find(method, fileupload_guid) : send(method) asset ||= send("build_#{method}") if respond_to?("build_#{method}") asset end end def fileuploads_columns self.class.fileuploads_columns end protected def fileuploads_update fileuploads_columns.each do |method| self.class.fileupload_update(id, fileupload_guid, method) end end end end end