require 'active_support/concern' module HasContent extend ActiveSupport::Concern included do Rails.application.config.content_types[:all].each do |content_type| content_type_sym = content_type.name.downcase.pluralize.to_sym # :characters #has_many :characters, :locations, etc has_many content_type_sym, dependent: :destroy end has_many :timelines has_many :attribute_fields has_many :attribute_categories has_many :attribute_values, class_name: 'Attribute', dependent: :destroy # { # characters: [...], # locations: [...] # } def content( content_types: Rails.application.config.content_types[:all].map(&:name), page_scoping: { user_id: self.id }, universe_id: nil ) return {} if content_types.empty? polymorphic_content_fields = [:id, :name, :page_type, :user_id, :created_at, :updated_at, :deleted_at, :archived_at, :privacy] where_conditions = page_scoping.map { |key, value| "#{key} = #{value}" }.join(' AND ') + ' AND deleted_at IS NULL AND archived_at IS NULL' sql = content_types.uniq.map do |page_type| if page_type != 'Universe' # Even though we're selecting universe_id here, it's still absent from all of the result rows. No idea why. # Removing Universe from `content_types` and adding universe_id to the content_fields works, so maybe it's something to # do with UNIONing the NULL column? # clause = "SELECT #{polymorphic_content_fields.join(',')},universe_id FROM #{page_type.downcase.pluralize} WHERE #{where_conditions}" clause = "SELECT #{polymorphic_content_fields.join(',')} FROM #{page_type.downcase.pluralize} WHERE #{where_conditions}" else # clause = "SELECT #{polymorphic_content_fields.join(',')},id FROM #{page_type.downcase.pluralize} WHERE #{where_conditions}" clause = "SELECT #{polymorphic_content_fields.join(',')} FROM #{page_type.downcase.pluralize} WHERE #{where_conditions}" end if universe_id.present? && page_type != 'Universe' clause += " AND universe_id = #{universe_id}" end clause end.compact.join(' UNION ALL ') + ' ORDER BY page_type, id' result = ActiveRecord::Base.connection.execute(sql) @content_by_page_type ||= result.to_a.each_with_object({}) do |object, hash| object.keys.each do |key| object.except!(key) if key.is_a?(Integer) end hash[object['page_type']] ||= [] hash[object['page_type']] << ContentPage.new(object) end end # [..., ...] def content_list( content_types: Rails.application.config.content_types[:all].map(&:name), page_scoping: { user_id: self.id } ) # todo we can't select for universe_id here which kind of sucks, so we need to research 1) the repercussions, 2) what to do instead polymorphic_content_fields = [:id, :name, :page_type, :user_id, :created_at, :updated_at, :deleted_at, :archived_at, :privacy] where_conditions = page_scoping.map { |key, value| "#{key} = #{value}" }.join(' AND ') + ' AND deleted_at IS NULL AND archived_at IS NULL' sql = content_types.uniq.map do |page_type| "SELECT #{polymorphic_content_fields.join(',')} FROM #{page_type.downcase.pluralize} WHERE #{where_conditions}" end.join(' UNION ALL ') @user_content_list ||= ActiveRecord::Base.connection.execute(sql) end # { # characters: [...], # locations: [...] # } def content_in_universe universe_id @user_content_in_universe ||= content_list(page_scoping: { user_id: self.id, universe_id: universe_id }).group_by(&:page_type) end # 5 def content_count @user_content_count ||= content_list.count end # { # characters: [...], # locations: [...], # } def public_content @user_public_content ||= begin content_value = {} Rails.application.config.content_types[:all].each do |type| relation = type.name.downcase.pluralize.to_sym # :characters content_value[relation] = send(relation).is_public end content_value end end # 8 def public_content_count @user_content_count ||= begin Rails.application.config.content_types[:all].map do |type| relation = type.name.downcase.pluralize.to_sym # :characters send(relation).is_public.count end.sum end end # [..., ..., ...] def recent_content_list(limit: 10) # Todo: I think this is more optimized, but the group introduces weird # ordering of the results, so we're building it a bit less optimized below # just to ensure it's actually correct. # recently_changed_attributes = Attribute.where(user: self) # .order('updated_at desc') # .group([:entity_type, :entity_id]) # .limit(10) recently_changed_attributes = Attribute.where(user: self) .order('updated_at desc') .limit(limit * 100) .group_by { |r| [r.entity_type, r.entity_id] } .keys .first(limit) @user_recent_content_list = recently_changed_attributes.map do |entity_type, entity_id| entity_type.constantize.find_by(id: entity_id) rescue nil end.compact end def recent_content_list_by_create(limit: 10) # Todo: I think this is more optimized, but the group introduces weird # ordering of the results, so we're building it a bit less optimized below # just to ensure it's actually correct. # recently_changed_attributes = Attribute.where(user: self) # .order('updated_at desc') # .group([:entity_type, :entity_id]) # .limit(10) recently_changed_attributes = Attribute.where(user: self) .order('created_at desc') .limit(limit * 100) .group_by { |r| [r.entity_type, r.entity_id] } .keys .first(limit) @user_recent_content_list = recently_changed_attributes.map do |entity_type, entity_id| entity_type.constantize.find_by(id: entity_id) end.compact end end end