require 'active_support/concern' module SocialStream module Models # {Subject Subjects} are subtypes of {Actor}. {SocialStream} provides two # {Subject Subjects}, {User} and {Group} # # Each {Subject} is defined in +config/initializers/social_stream.rb+ # # This module provides additional features for models that are subjects, # extending them. Including the module in each {Subject} model is not required! # After declared in +config/initializers/social_stream.rb+, {SocialStream} is # responsible for adding subject features to each model. # # = Scopes # There are several scopes available for subjects # # alphabetic:: sort subjects by name # name_search:: simple search by name # distinct_initials:: get only the first letter of the name # followed:: sort by most following incoming {Tie ties} # liked:: sort by most likes # module Subject extend ActiveSupport::Concern included do belongs_to :actor, :validate => true, :autosave => true, :dependent => :destroy has_one :profile, :through => :actor validates_presence_of :name accepts_nested_attributes_for :profile scope :alphabetic, joins(:actor).merge(Actor.alphabetic) scope :letter, lambda{ |param| joins(:actor).merge(Actor.letter(param)) } scope :name_search, lambda{ |param| joins(:actor).merge(Actor.name_search(param)) } scope :tagged_with, lambda { |param| if param.present? joins(:actor => :activity_object).merge(ActivityObject.tagged_with(param)) end } scope :distinct_initials, joins(:actor).merge(Actor.distinct_initials) scope :followed, lambda { joins(:actor). order("actors.follower_count DESC") } scope :liked, lambda { joins(:actor => :activity_object). order('activity_objects.like_count DESC') } scope :most, lambda { |m| types = %w( followed liked ) if types.include?(m) __send__ m end } end module InstanceMethods def actor! actor || build_actor(:subject_type => self.class.to_s) end def to_param slug end # Delegate missing methods to {Actor}, if they exist there def method_missing(method, *args, &block) super rescue NameError => subject_error # These methods must be raised to avoid loops (the :actor association calls here again) exceptions = [ :_actor_id ] raise subject_error if exceptions.include?(method) actor!.__send__ method, *args, &block end # {Actor} handles some methods def respond_to? *args super || actor!.respond_to?(*args) end end module ClassMethods def find_by_slug(perm) includes(:actor).where('actors.slug' => perm).first end def find_by_slug!(perm) find_by_slug(perm) || raise(ActiveRecord::RecordNotFound) end end end end end