module ActionStore::Mixin::ClassMethods
Attributes
defined_actions[R]
Public Instance Methods
action_store(action_type, name, class_name: nil, action_class_name: "Action", counter_cache: nil, user_counter_cache: nil)
click to toggle source
# File lib/action_store/mixin.rb, line 36 def action_store(action_type, name, class_name: nil, action_class_name: "Action", counter_cache: nil, user_counter_cache: nil) name = name.to_s class_name ||= name.classify target_klass = class_name.constantize action_klass = action_class_name.constantize action_type = action_type.to_s if counter_cache == true # @post.stars_count counter_cache = "#{action_type.pluralize}_count" end if user_counter_cache == true # @user.star_posts_count user_counter_cache = "#{action_type}_#{name.pluralize}_count" end @defined_actions ||= [] action = { action_name: name, action_type: action_type, action_klass: action_klass, target_klass: target_klass, target_type: target_klass.name, counter_cache: counter_cache, user_counter_cache: user_counter_cache } @defined_actions << action define_relations(action_klass: action_klass, target_klass: target_klass, action_type: action_type, action_name: name) end
create_action(action_type, opts)
click to toggle source
# File lib/action_store/mixin.rb, line 80 def create_action(action_type, opts) opts[:action_type] = action_type opts = safe_action_opts(opts) return false if opts[:user_id].blank? || opts[:user_type].blank? return false if opts[:target_id].blank? || opts[:target_type].blank? defined_action = find_defined_action(opts[:action_type], opts[:target_type]) return false if defined_action.nil? # create! for raise RecordNotUnique begin action = defined_action[:action_klass].find_or_create_by!(where_opts(opts)) action.update(action_option: opts[:action_option]) if opts.key?(:action_option) rescue ActiveRecord::RecordNotUnique # update action_option on exist action = defined_action[:action_klass].where(where_opts(opts)).take action.update(action_option: opts[:action_option]) if opts.key?(:action_option) end reset_counter_cache(action, defined_action) true end
destroy_action(action_type, opts)
click to toggle source
# File lib/action_store/mixin.rb, line 103 def destroy_action(action_type, opts) opts[:action_type] = action_type opts = safe_action_opts(opts) return false if opts[:user_id].blank? || opts[:user_type].blank? return false if opts[:target_id].blank? || opts[:target_type].blank? defined_action = find_defined_action(opts[:action_type], opts[:target_type]) return false if defined_action.nil? action = defined_action[:action_klass].where(where_opts(opts)).first return true unless action action.destroy reset_counter_cache(action, defined_action) true end
find_action(action_type, opts)
click to toggle source
# File lib/action_store/mixin.rb, line 68 def find_action(action_type, opts) opts[:action_type] = action_type opts = safe_action_opts(opts) return nil if opts[:user_id].blank? || opts[:user_type].blank? return nil if opts[:target_id].blank? || opts[:target_type].blank? defined_action = find_defined_action(opts[:action_type], opts[:target_type]) return nil if defined_action.nil? defined_action[:action_klass].find_by(where_opts(opts)) end
find_defined_action(action_type, target_type)
click to toggle source
# File lib/action_store/mixin.rb, line 28 def find_defined_action(action_type, target_type) action_type = action_type.to_s name = target_type.to_s.singularize.underscore defined_actions.find do |a| a[:action_type] == action_type && (a[:action_name] == name || a[:target_type] == target_type) end end
reset_counter_cache(action, defined_action)
click to toggle source
# File lib/action_store/mixin.rb, line 120 def reset_counter_cache(action, defined_action) return false if action.blank? if defined_action[:counter_cache] && action.target.present? target_count = defined_action[:action_klass].where( action_type: defined_action[:action_type], target_type: action.target_type, target_id: action.target_id ).count action.target.update_attribute(defined_action[:counter_cache], target_count) end if defined_action[:user_counter_cache] && action.user.present? user_count = defined_action[:action_klass].where( action_type: defined_action[:action_type], target_type: action.target_type, user_type: action.user_type, user_id: action.user_id ).count action.user.update_attribute(defined_action[:user_counter_cache], user_count) end end
Private Instance Methods
define_relations(target_klass:, action_klass:, action_type:, action_name:)
click to toggle source
# File lib/action_store/mixin.rb, line 145 def define_relations(target_klass:, action_klass:, action_type:, action_name:) user_klass = self # user, person user_name = user_klass.table_name.underscore.singularize # like_topic, follow_user full_action_name = [action_type, action_name].join("_") # like_user, follow_user full_action_name_for_target = [action_type, "by", user_name].join("_") # unlike_topic, unfollow_user unaction_name = "un#{full_action_name}" # @target.like_topic_actions, @target.follow_user_actions has_many_name = [full_action_name, "actions"].join("_").to_sym # @target.like_topics, @target.follow_users has_many_through_name = full_action_name.pluralize.to_sym # @user.like_by_user_actions, @user.follow_by_user_actions has_many_name_for_target = [full_action_name_for_target, "actions"].join("_").to_sym # @user.like_by_users, @user.follow_by_users has_many_through_name_for_target = full_action_name_for_target.pluralize.to_sym has_many_scope = lambda { where(action_type: action_type, target_type: target_klass.name, user_type: user_klass.name) } # User has_many :like_topic_actions user_klass.send :has_many, has_many_name, has_many_scope, class_name: action_klass.name, foreign_key: "user_id" # User has_many :like_topics user_klass.send :has_many, has_many_through_name, through: has_many_name, source: :target, source_type: target_klass.name # Topic has_many :like_user_actions target_klass.send :has_many, has_many_name_for_target, has_many_scope, foreign_key: :target_id, class_name: action_klass.name # Topic has_many :like_users target_klass.send :has_many, has_many_through_name_for_target, through: has_many_name_for_target, source_type: user_klass.name, source: :user # @user.like_topic user_klass.send(:define_method, full_action_name) do |target_or_id| target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id result = user_klass.create_action(action_type, target_type: target_klass.name, target_id: target_id, user: self) target_or_id.reload if target_or_id.is_a?(target_klass) reload result end # @user.like_topic? user_klass.send(:define_method, "#{full_action_name}?") do |target_or_id| target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id result = user_klass.find_action(action_type, target_type: target_klass.name, target_id: target_id, user: self) result.present? end # @user.unlike_topic user_klass.send(:define_method, unaction_name) do |target_or_id| target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id result = user_klass.destroy_action(action_type, target_type: target_klass.name, target_id: target_id, user: self) target_or_id.reload if target_or_id.is_a?(target_klass) reload result end end
safe_action_opts(opts)
click to toggle source
# File lib/action_store/mixin.rb, line 224 def safe_action_opts(opts) opts ||= {} if opts[:user] opts[:user_id] = opts[:user].id opts[:user_type] = opts[:user].class.name end if opts[:target] opts[:target_type] = opts[:target].class.name opts[:target_id] = opts[:target].id end opts end
where_opts(opts)
click to toggle source
# File lib/action_store/mixin.rb, line 237 def where_opts(opts) opts.extract!(:action_type, :target_type, :target_id, :user_id, :user_type) end