Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ ActsAsEventable makes it easy to log events corresponding to actions taken on ac

in your controller (typically application_controller)

class FooController
class FooController
record_events
# or

# or

record_events lambda { something_that_returns_a_user }
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
class ActsAsEventableMigrationGenerator < Rails::Generator::Base
def manifest
record do |m|
class ActsAsEventableMigrationGenerator < Rails::Generator::Base
def manifest
record do |m|
m.migration_template 'migration.rb', 'db/migrate'
end
end

def file_name
"acts_as_eventable_migration"
end
Expand Down
12 changes: 6 additions & 6 deletions generators/acts_as_eventable_migration/templates/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ def self.up
create_table :events do |t|
t.string :eventable_type, :null => false
t.integer :eventable_id

t.integer :user_id

# this is for when the action is destroy
t.text :eventable_attributes

# this is for identifying and clustering batch updates
t.integer :batch_parent_id
t.integer :batch_size, :null => false, :default => 1

t.string :action, :null => false

t.datetime :created_at, :null => false
end

add_index :events, [:eventable_type, :eventable_id]
add_index :events, [:batch_parent_id, :user_id]
end

def self.down
drop_table :events
end
Expand Down
62 changes: 31 additions & 31 deletions lib/acts_as_eventable/active_record.rb
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
# ActsAsEventable
module ActsAsEventable
module ActiveRecord

def self.included(base)
base.extend ActsMethods
end

module ActsMethods
def acts_as_eventable(options={}, &block)
if self.respond_to?(:acts_as_eventable_options)
raise "acts_as_eventable cannot be used twice on the same model"
else
options[:block] = block

write_inheritable_attribute :acts_as_eventable_options, options
class_inheritable_reader :acts_as_eventable_options

has_many :events, :as => :eventable, :order => 'id desc'

after_update :event_update
after_create :event_create
before_destroy :event_destroy # use before instead of after in case we want to access association before they are destroyed

include BatchingMethods
include InstanceMethods
# We need to alias these method chains

# We need to alias these method chains
# to manage batch events
alias_method_chain :save, :batch
alias_method_chain :save!, :batch
alias_method_chain :destroy, :batch
end
end
end

module BatchingMethods
def save_with_batch(*args) #:nodoc:
batch { save_without_batch(*args) }
Expand All @@ -42,13 +42,13 @@ def save_with_batch(*args) #:nodoc:
def save_with_batch!(*args) #:nodoc:
batch { save_without_batch!(*args) }
end

def destroy_with_batch(*args)
batch { destroy_without_batch(*args) }
end

private

# This saves the batch events in the correct order with the correct
# batch id
def save_batch_events
Expand All @@ -64,11 +64,11 @@ def save_batch_events
batch_size += 1
end
end

# set the batch size of the parent
::Event.update_all({:batch_size=>batch_size},{:id=>batch_parent_id}) if batch_parent_id
::Event.update_all({:batch_size=>batch_size},{:id=>batch_parent_id}) if batch_parent_id
end

def batch(&block)
status = nil
if batch_event_state.empty?
Expand All @@ -85,38 +85,38 @@ def batch(&block)
end
status
end

def batch_event_queue
batch_event_state[:queue] ||= []
end

def batch_events
batch_event_state[:events] ||= {}
end

def clear_batch_event_state
Thread.current['batch_event_state'] = {}
end

def batch_event_state
Thread.current['batch_event_state'] ||= {}
end
end

module InstanceMethods

# This is to be used for recording arbitrary events as necessary
# like when a post is published, or a user logs in.
def record_event!(action)
event = build_event(action)
raise "Cannot record an event on new records" if new_record?
event.save!
end

private
# Destroys all the old events and creates a
# new destroy event that also captures the eventable_attributes

# Destroys all the old events and creates a
# new destroy event that also captures the eventable_attributes
# so that the record can still be shown in the event log.
def event_destroy
transaction do
Expand All @@ -126,7 +126,7 @@ def event_destroy
batch_events[self] = event
end
end

# Saves the event after assigning eventable
def event_update
event = build_event('updated')
Expand All @@ -135,29 +135,29 @@ def event_update
batch_events[self] = event
end
end

def event_create
event = build_event('created')
batch_events[self] = event
end

# Builds the initial event and sets the default
# action type. Does not assign eventable yet because
# it may not have been saved if this was a new record.
def build_event(action)
event = ::Event.new
event.eventable = self
event.action = action

# Allow the eventable model class to modify the event record before it
# is saved to do things like assign the current user
if block = self.class.acts_as_eventable_options[:block]
block.call(self, event)
end

return event
end
end

end
end
26 changes: 13 additions & 13 deletions lib/acts_as_eventable/event/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Event
module Base
def self.included(base)
base.class_eval do

# Attribute Modifiers
# -------------------

Expand All @@ -28,7 +28,7 @@ def self.included(base)
# ---------

before_save :clear_eventable_id, :if => Proc.new {|e| e.action == "destroyed"}

# Finders
# -------

Expand All @@ -37,19 +37,19 @@ def self.included(base)
named_scope :by_user, lambda {|user| {:conditions => {:user_id => user.id}}}
named_scope :with_users, :include => :user
named_scope :with_eventables, :include => :eventable

extend ClassMethods

# This is redefined so that it returns the eventable
# object even if it has been destroyed by reconstructing
# it from the eventable attributes that were saved
# on the event
alias_method :eventable_when_not_destroyed, :eventable

include InstanceMethods
end
end

module ClassMethods
# This will replace the way rails includes the eventable
# association with the inject_eventables method below.
Expand Down Expand Up @@ -92,17 +92,17 @@ def inject_eventables(events, &block)
end
end

private
private

# If options contains includes for eventable, removes it
# and return true. Otherwise, returns false.
def remove_eventable_from_includes(options)
inject = false
if options
case includes = options[:include]
when Array then
when Array then
inject = !includes.delete(:eventable).nil?
when Symbol
when Symbol
if includes == :eventable
options.delete(:include)
inject = true
Expand All @@ -112,7 +112,7 @@ def remove_eventable_from_includes(options)
return inject
end
end

module InstanceMethods
def eventable
if eventable_id.nil? && !eventable_attributes.nil?
Expand All @@ -121,15 +121,15 @@ def eventable
eventable_when_not_destroyed
end
end

private

# Used to clear the eventable id on destroy events
def clear_eventable_id
self.eventable_id = nil
end
end

end # Base
end # Event
end # ActsAsEventable
Loading