module Polygallery module HasPolygallery extend ActiveSupport::Concern DEFAULTS = { :associations => { :gallery => { :class_name => '::Polygallery::Gallery', :as => :galleryable, :dependent => :destroy }, :photos => { :class_name => '::Polygallery::Photo', :before_add => :set_nest, :dependent => :destroy, :foreign_key => :gallery_id } }, :association_names => { :gallery => :gallery, :photos => :photos }, :nested_attributes => { :gallery => { :reject_if => :all_blank }, :photos => { :reject_if => proc {|attributes| !attributes.key?('id') && attributes['photo'].nil? }, :allow_destroy => true } }, :validates => {}, :paperclip => { :styles => {:medium => '300x300#', :thumb => '100x100#'}, :default_url => 'polygallery/thumbnail-missing.jpg' }, :paperclip_validations => { :content_type => /\Aimage\/.*\Z/, :presence => false } } included do end module ClassMethods def has_polygallery(title='gallery', options={}) if title.is_a? Hash options = title title = 'gallery' end # associations = options[:associations] # gallery_association = options[:associations][:gallery] if associations.present? # gallery_class_name = gallery_association[:class_name] if gallery_association.present? defaults = HasPolygallery::DEFAULTS if options[:association_names].nil? && title.to_s != 'gallery' options[:association_names] = { :gallery => :"#{title}", :photos => :"#{title.to_s.gsub('_gallery', '')}_photos" } end settings = defaults.deep_merge(options) cattr_accessor "#{title}_settings".to_sym send("#{title}_settings=".to_sym, settings) has_one title.to_sym, -> { where(:title => title.to_s) }, settings[:associations][:gallery] has_many settings[:association_names][:photos], :through => :"#{title}", :source => settings[:association_names][:photos], :class_name => settings[:associations][:photos][:class_name] accepts_nested_attributes_for settings[:association_names][:gallery], settings[:nested_attributes][:gallery] accepts_nested_attributes_for settings[:association_names][:photos], settings[:nested_attributes][:photos] after_initialize :build_galleries before_save :ensure_galleryable_set include HasPolygallery::LocalInstanceMethods end def polygalleries self.reflect_on_all_associations(:has_one) .select{|a| a.foreign_key == 'galleryable_id'}.map(&:name) end def has_polygallery?(gallery_title=nil) return polygalleries.any? if gallery_title.nil? polygalleries.include?(gallery_title) end # def new(*args) # super(*args) # end end module LocalInstanceMethods def polygalleries # TODO: use association reflections instead of direct class selection Gallery.select('polygallery_galleries.title') .where(:galleryable => self) .group('polygallery_galleries.title') .map(&:title) end def has_polygallery?(gallery_title=nil) return polygalleries.any? if gallery_title.nil? polygalleries.include?(gallery_title) end def build_galleries return unless self.class.has_polygallery? self.class.polygalleries.each do |pg| gallery_association = send pg next if gallery_association.present? gallery_settings = self.send :"#{pg.to_s}_settings" if gallery_association.nil? built_gallery = send :"build_#{pg.to_s}", :polygallery_options => gallery_settings gallery_association = send :"#{pg.to_s}=", built_gallery end gallery_association.galleryable ||= self end end def build_first_photos return unless self.class.has_polygallery? self.class.polygalleries.each {|pg| send(pg).build_first_photo } end def first_photo return unless self.class.has_polygallery? first_p = nil self.class.polygalleries.each do |pg| gallery_settings = send :"#{pg.to_s}_settings" ptos = send(gallery_settings[:association_names][:photos]) .select{|p| p.photo.file? } next if ptos.empty? first_p = ptos.first.photo break end first_p || Photo.new.photo end def ensure_galleryable_set self.class.polygalleries.each do |pg| gallery_association = self.send :"#{pg}" gallery_association.galleryable ||= self gallery_association.polygallery_photos.each do |pp| pp.galleryable ||= self end end end end end end ActiveRecord::Base.send :include, Polygallery::HasPolygallery