require 'polygallery' module Polygallery module HasPolyphotos extend ActiveSupport::Concern module ClassMethods def has_polyphotos(title=nil, options={}) attr_accessor :polygallery_options defaults = self.polygallery_settings association_names = (options[:association_names].present? ? options : defaults)[:association_names] title ||= association_names[:photos].to_s if title.is_a? Hash options = title title = association_names[:photos].to_s end attr_accessor :photos_attributes, :photos_built settings = defaults.deep_merge options # init_associations settings belongs_to :galleryable, polymorphic: true # photos_name = settings[:association_names][:photos] has_many :photos, settings[:associations][:photos].symbolize_keys after_initialize do self.polygallery_options ||= self.polygallery_settings self.initialize_polygallery end after_initialize :build_polygallery_photos, :if => :new_record? before_validation :set_nested_attributes_to_correct_gallery before_validation :build_polygallery_photos, :unless => :photos_built? # , :on => :update before_validation :prune_empty_photos include HasPolyphotos::LocalInstanceMethods end def polygallery_settings DEFAULT_SETTINGS end def init_associations(settings=DEFAULT_SETTINGS) belongs_to :galleryable, :polymorphic => true photos_name = settings[:association_names][:photos] has_many :photos, settings[:associations][:photos].symbolize_keys # has_many photos_name, settings[:associations][:photos].symbolize_keys accepts_nested_attributes_for :photos, settings[:nested_attributes][:photos].symbolize_keys attr_accessor :"#{photos_name.to_s}_attributes" end end module LocalInstanceMethods def set_nest(photo) photo.galleryable_id ||= galleryable_id photo.galleryable_type ||= galleryable_type photo.galleryable ||= galleryable photo.gallery_title ||= title photo.polygallery_options ||= self.polygallery_settings photo.initialize_polyphoto photo.send(:"#{title}=", self) if photo.send(:"#{title}").nil? end def include_polygallery_settings(settings) self.polygallery_options = settings self.initialize_polygallery end def initialize_polygallery settings = self.polygallery_settings self.class.init_associations(settings) end def build_first_photo photo_association = self.polygallery_photos photo_association.build( :polygallery_options => self.polygallery_settings, :galleryable => self.galleryable, :gallery_title => self.title ) unless photo_association.any? end def polygallery_settings return self.polygallery_options if self.polygallery_options.present? return Kernel.const_get(self.galleryable_type) .send(:"#{self.title}_settings") if galleryable_type.present? self.class.polygallery_settings end def polygallery_photos_name self.polygallery_settings[:association_names][:photos] end def polygallery_photos; photos end # send self.polygallery_photos_name end def polygallery_photos_attributes; self.photos_attributes end # self.send :"#{polygallery_photos_name.to_s}_attributes" end def polygallery_photos_attributes=(v); self.photos_attributes = v end # self.send :"#{polygallery_photos_name.to_s}_attributes=", v end def polygallery_photos_classname self.polygallery_settings[:associations][:photos][:class_name] end def polygallery_photos_class Object.const_get polygallery_photos_classname end def set_nested_attributes_to_correct_gallery if self.photos_attributes.present? && self.polygallery_photos_name.to_s != 'photos' # self.send :"#{polygallery_photos_name.to_s}_attributes=", self.photos_attributes # self.photos_attributes = nil end end def build_polygallery_photos # Convert attributes to array if in hash form # self.photos_attributes = # self.photos_attributes.map{|_, v| v # } if self.photos_attributes.is_a? Hash # Initialize a duplicate attrs_for_photos = if self.photos_attributes.is_a? Hash self.photos_attributes.values else ( self.photos_attributes || [] ).dup end return unless attrs_for_photos.any? return if self.photos_built? attrs_for_photos.each_with_index do |attrs_for_photo, index| attrs_for_photo[:polygallery_options] = self.polygallery_settings should_destroy = %w(true 1).include? attrs_for_photo.delete(:_destroy) if attrs_for_photo.key? :id existing_id = attrs_for_photo.delete(:id).to_i existing_photo = self.polygallery_photos_class.find existing_id if should_destroy # puts 'Destroying a photo' existing_photo.destroy else # puts 'Updating an existing photo' existing_photo.update_attributes attrs_for_photo end else # puts 'Building a new photo' self.polygallery_photos.build attrs_for_photo end end self.photos_built = true end def photos_built?; self.photos_built.present? end def prune_empty_photos # puts "#{title} is pruning empty photos..." polygallery_photos.each {|pp| if pp.new_record? && !pp.photo.file? && pp.photo_to_upload.nil? # puts 'Marking photo for destruction' pp.mark_for_destruction polygallery_photos.delete pp end } end def remote_urls(style=nil); photos.map{|p| p.remote_url style } || [] end def thumb_url; first_photo.thumb_url end def first_photo # TODO: some kind of selection photos.first || Photo.new end def method_missing(m, *args, &block) if m == :photos self.initialize_polygallery return send(m, *args, &block) if self.respond_to? m Photo.where('1 = 0') else super end end end end end # ActiveRecord::Base.send :include, Polygallery::HasPolyphotos