Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit. Migrated from other projects written a year or two ago.

  • Loading branch information...
commit 353c5ce7cb9477aea6fb5cf9f5b7202cf3c2cc31 0 parents
@krisr authored
1  .gitignore
@@ -0,0 +1 @@
+rdoc/*
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Kris Rasmussen
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5 README
@@ -0,0 +1,5 @@
+== ActsAsEventable
+
+ActsAsEventable makes it easy to log events corresponding to actions taken on active record models.
+
+Copyright (c) 2009 Kris Rasmussen, released under the MIT license
11 Rakefile
@@ -0,0 +1,11 @@
+require 'rake'
+require 'spec/rake/spectask'
+
+desc 'Default: run specs.'
+task :default => :spec
+
+desc 'Run the specs'
+Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end
11 generators/acts_as_eventable_migration/acts_as_eventable_migration_generator.rb
@@ -0,0 +1,11 @@
+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
+end
29 generators/acts_as_eventable_migration/templates/migration.rb
@@ -0,0 +1,29 @@
+class ActsAsEventableMigration < ActiveRecord::Migration
+ def self.up
+ create_table :events do |t|
+ t.string :eventable_type, :null => false
+ t.integer :eventable_id
+
+ t.integer :user_id, :null => false
+
+ # 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]
+ add_index :events, :batch_parent_id
+ end
+
+ def self.down
+ drop_table :events
+ end
+end
11 init.rb
@@ -0,0 +1,11 @@
+# we do not require event because rails will autoload it
+# if we require it here it will not be reloaded in development
+# mode and that will cause problems with the User reference
+require 'acts_as_eventable_options'
+require 'acts_as_eventable_action_controller'
+require 'acts_as_eventable_active_record'
+
+ActiveRecord::Base.send(:include, ActsAsEventable::ActiveRecord)
+ActionController::Base.send(:include, ActsAsEventable::ActionController)
+
+ActiveSupport::Dependencies.load_once_paths.delete lib_path
1  install.rb
@@ -0,0 +1 @@
+# Install hook code here
36 lib/acts_as_eventable_action_controller.rb
@@ -0,0 +1,36 @@
+module ActsAsEventable
+ module ActionController
+
+ def self.included(base) # :nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def record_events(&event_user)
+ write_inheritable_attribute('event_user', &event_user) if block_given?
+
+ around_filter :setup_event_user
+
+ include InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+ private
+
+ def setup_event_user
+ user = begin
+ if block = self.class.read_inheritable_attribute('event_user')
+ block.call(self)
+ elsif self.respond_to? :current_user
+ current_user
+ else
+ raise "record_events: you must pass a block to fetch the current user or define a 'current_user' method"
+ end
+ end
+
+ Event.record_events(user) {yield}
+ end
+ end
+ end
+end
170 lib/acts_as_eventable_active_record.rb
@@ -0,0 +1,170 @@
+# ActsAsEventable
+module ActsAsEventable
+ module ActiveRecord
+
+ def self.included(base)
+ base.extend ActsMethods
+ end
+
+ module ActsMethods
+ def acts_as_eventable(options={})
+ write_inheritable_attribute :acts_as_eventable_options, options
+ class_inheritable_reader :acts_as_eventable_options
+
+ has_many :events, :as => :eventable, :order => 'id desc'
+
+ before_save :event_build
+ after_save :event_save
+ before_destroy :event_destroy # use before instead of after in case we want to access association before they are destroyed
+
+ include BatchingMethods
+ include InstanceMethods
+ extend ClassMethods
+
+ # 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
+
+ module ClassMethods
+ # This is mainly here so we know that we
+ # can detect if something is eventable,
+ # but also as a convience
+ def event_user
+ Event.event_user
+ end
+ end
+
+ module BatchingMethods
+ def save_with_batch(*args) #:nodoc:
+ batch { save_without_batch(*args) }
+ end
+
+ 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
+ batch_parent_id = nil
+ batch_size = 0
+ batch_event_queue.each do |record|
+ event = batch_events[record]
+ if event
+ event.batch_parent_id = batch_parent_id
+ event.save!
+ logger.debug "Recorded #{event.eventable_type} #{event.action} event with batch parent id = #{batch_parent_id}"
+ batch_parent_id ||= event.id
+ 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
+ end
+
+ def batch(&block)
+ status = nil
+ if batch_event_state.empty?
+ begin
+ batch_event_queue << self
+ status = block.call
+ save_batch_events if status
+ ensure
+ clear_batch_event_state
+ end
+ else
+ batch_event_queue << self
+ status = block.call
+ 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_user=nil)
+ event_user ||= self.class.event_user
+
+ raise "Cannot record an event without an event user!" unless event_user
+ raise "Cannot record an event on new records" if new_record?
+
+ @event = Event.new
+ @event.action = action
+ @event.user = event_user
+ @event.eventable = self
+ @event.save!
+ end
+
+ private
+
+ # 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
+ self.events.destroy_all
+
+ if event_user = self.class.event_user
+ @event = Event.new
+ @event.action = 'destroyed'
+ @event.eventable = self
+ @event.eventable_attributes = self.attributes
+ @event.user = event_user
+ batch_events[self] = @event
+ end
+ 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 event_build
+ if event_user = self.class.event_user
+ @event = Event.new
+ @event.action = case
+ when self.new_record? then 'created'
+ else 'updated'
+ end
+ @event.user = event_user
+ end
+ end
+
+ # Saves the event after assigning eventable
+ def event_save
+ updated_if = acts_as_eventable_options[:updated_if]
+ if @event && !(@event.action == 'updated' && updated_if && !updated_if.call(self))
+ @event.eventable = self
+ batch_events[self] = @event
+ end
+ end
+ end
+
+ end
+end
10 lib/acts_as_eventable_options.rb
@@ -0,0 +1,10 @@
+module ActsAsEventable
+ class Options
+ # This can be configured from an initializer as needed
+ # for example, to add a clause for acts_as_paranoid
+ # so it still selects deleted users or to specify
+ # the class_name
+ @@event_belongs_to_user_options = {}
+ cattr_accessor :event_belongs_to_user_options
+ end
+end
157 lib/event.rb
@@ -0,0 +1,157 @@
+class Event < ActiveRecord::Base
+
+ # Attribute Modifiers
+ # -------------------
+
+ serialize :eventable_attributes
+
+ # Relationships
+ # -------------
+
+ belongs_to :eventable, :polymorphic => true
+ belongs_to :user, ActsAsEventable::Options.event_belongs_to_user_options.merge(:foreign_key => 'user_id')
+ has_many :child_batch_events, :class_name => 'Event', :foreign_key => 'batch_parent_id', :dependent => :destroy
+
+ # Validation
+ # ----------
+
+ validates_presence_of :action, :eventable_type, :user_id # we do not require eventable_id since we won't have it on destroy actions
+ validates_length_of :action, :maximum => 255, :allow_blank => true
+ validates_presence_of :eventable_id, :if => Proc.new {|e| e.action != 'destroyed'}
+ validates_presence_of :eventable_attributes, :if => Proc.new {|e| e.action == 'destroyed'}
+
+ # Callbacks
+ # ---------
+
+ before_save :clear_eventable_id, :if => Proc.new {|e| e.action == "destroyed"}
+
+ # Finders
+ # -------
+
+ class <<self
+
+ # This will replace the way rails includes the eventable
+ # association with the inject_eventables method below.
+ def find_with_eventables(*args)
+ options = args.extract_options!
+
+ inject = false
+
+ # see if eventable was meant to be included
+ inject ||= remove_eventable_from_includes(options)
+ # puts the options back
+ args << options
+
+ # now check and see if it was in the scopes
+ inject ||= remove_eventable_from_includes(scope(:find))
+
+ result = find_without_eventables(*args)
+ inject_eventables(result) if inject
+ result
+ end
+
+ # Adds the eventable records to events, but attempts to
+ # select all events of the same type at once
+ def inject_eventables(events, &block)
+ if events
+ array = events.is_a?(Array)
+ events = [events] if !array
+ events_by_eventable_type = events.group_by &:eventable_type
+ events_by_eventable_type.each do |eventable_type, events|
+ events_by_eventable_id = events.group_by &:eventable_id
+ ids = events_by_eventable_id.keys.compact
+ klass = eventable_type.constantize
+ klass = klass.for_events if klass.respond_to? :for_events
+ eventables = klass.find(ids)
+ eventables.each do |eventable|
+ events_by_eventable_id[eventable.id].each { |event| event.set_eventable_target(eventable) }
+ end
+ end
+ array ? events : events.first
+ end
+ end
+
+ alias_method_chain :find, :eventables
+
+
+ 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
+ inject = !includes.delete(:eventable).nil?
+ when Symbol
+ if includes == :eventable
+ options.delete(:include)
+ inject = true
+ end
+ end
+ end
+ inject
+ end
+ end
+
+
+
+ named_scope :batched, :conditions => {:batch_parent_id => nil}
+ named_scope :by_batch, lambda {|batch_parent_id| {:conditions => {:batch_parent_id => batch_parent_id}}}
+ named_scope :by_user, lambda {|user| {:conditions => {:user_id => user.id}}}
+ named_scope :with_users, :include => :user
+ named_scope :with_eventables, :include => :eventable
+
+ # Attribute overrides
+ # -------------------
+
+ # 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
+ def eventable
+ if eventable_id.nil? && !eventable_attributes.nil?
+ eventable_type.constantize.new(eventable_attributes)
+ else
+ eventable_when_not_destroyed
+ end
+ end
+
+ # Event State
+ # -----------
+ # These methods are used for setting the event user,
+ # see ActsAsEventable:ActionController for an example
+
+ def self.record_events(user, &block)
+ old_event_user = event_user
+ begin
+ self.event_user = user
+ yield
+ ensure
+ self.event_user = old_event_user
+ end
+ end
+
+ def self.event_user=(user)
+ eventable_state[:eventable_event_user] = user
+ end
+
+ def self.event_user
+ eventable_state[:eventable_event_user]
+ end
+
+
+ def self.eventable_state
+ Thread.current['eventable_state'] ||= {}
+ end
+
+ private
+
+ # Used to clear the eventable id on destroy events
+ def clear_eventable_id
+ self.eventable_id = nil
+ end
+
+end
222 spec/acts_as_eventable_spec.rb
@@ -0,0 +1,222 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe ActsAsEventable do
+ it "should mixin successfully" do
+ Form.acts_as_eventable
+ Field.acts_as_eventable
+ end
+end
+
+# TODO: still need to test update with nested records
+
+describe ActsAsEventable do
+ include UserSpecHelper
+ include FormSpecHelper
+
+ before(:each) do
+ @user = create_valid_user
+ end
+
+ describe "when event user is not set on create, save, destroy resource" do
+ before do
+ @form = Form.create!(valid_form_attributes)
+ @form.destroy
+ end
+
+ it "should not create any events" do
+ Event.count.should == 0
+ end
+ end
+
+ describe "when explicitly recording an event" do
+ before(:each) do
+ @form = Form.create!(valid_form_attributes)
+ end
+
+ describe "when the event user is not set" do
+ it "it should raise a Runtime Error" do
+ lambda { @form.record_event!('publish') }.should raise_error(RuntimeError, /without an event user/)
+ end
+ end
+
+ describe 'when the resource is new' do
+ it "should raise a Runtime Error" do
+ lambda { Form.new.record_event!('publish', @user) }.should raise_error(RuntimeError,/new record/)
+ end
+ end
+
+ it 'should create it successfully' do
+ @form.record_event!('publish',@user)
+ end
+ end
+
+ describe "when event user is set" do
+ before(:each) do
+ Event.event_user = @user
+ @form = Form.create!(valid_form_attributes)
+ end
+
+ describe "after create resource" do
+ it "should create an event for the resource with action create and no attributes saved" do
+ @form.events.length.should == 1
+ @form.events.first.action.should == 'created'
+ @form.events.first.eventable_attributes.should == nil
+ @form.events.first.eventable_id.should == @form.id
+ @form.events.first.eventable.should == @form
+ @form.events.first.batch_parent_id.should == nil
+ @form.events.first.batch_size.should == 1
+ end
+ end
+
+ describe "after update the resource" do
+ before(:each) do
+ @form.update_attributes(:title=>'Form Title Updated')
+ end
+
+ it "should create an event for the resource with action update and no attributes saved" do
+ @form.events.length.should == 2
+ @form.events.first.action.should == 'updated'
+ @form.events.first.eventable_attributes.should == nil
+ @form.events.first.eventable_id.should == @form.id
+ @form.events.first.eventable.should == @form
+ @form.events.first.batch_parent_id.should == nil
+ @form.events.first.batch_size.should == 1
+ end
+ end
+
+ describe "after update_attribute to update the resource" do
+ before(:each) do
+ @form.update_attribute(:title,'Form Title Updated')
+ end
+
+ it "should create an event for the resource with action update and no attributes saved" do
+ @form.events.length.should == 2
+ @form.events.first.action.should == 'updated'
+ @form.events.first.eventable_attributes.should == nil
+ @form.events.first.eventable_id.should == @form.id
+ @form.events.first.eventable.should == @form
+ @form.events.first.batch_parent_id.should == nil
+ @form.events.first.batch_size.should == 1
+ end
+ end
+
+ describe "after destroy the resource" do
+ before(:each) do
+ @form.destroy
+ end
+
+ it "should remove the existing events and create a new event with action destroy and attributes saved" do
+ Event.count.should == 1
+ event = Event.find(:first)
+ event.action.should == 'destroyed'
+ event.eventable_attributes.should_not == nil
+ event.eventable_attributes.should == @form.attributes
+
+ event.eventable.title == @form.title
+ event.eventable.created_at == @form.created_at
+ event.eventable.updated_at == @form.updated_at
+ event.batch_size.should == 1
+ end
+ end
+
+ describe "after destroy the resource when event user is not set" do
+ before(:each) do
+ Event.record_events(nil) do
+ @form.destroy
+ end
+ end
+
+ it "should remove the all events and not create a new one" do
+ Event.count.should == 0
+ end
+ end
+
+ describe "with nested events" do
+ before(:each) do
+ @base_event_count = Event.count
+ @form = Form.new(valid_form_attributes)
+ @field = @form.fields.build(valid_field_attributes)
+ @form.save!
+ end
+
+ it "should create two events total" do
+ (Event.count - @base_event_count).should == 2
+ end
+
+ it "should create an event for the form" do
+ @form.events.first.should_not == nil
+ end
+
+ it "should create an event for the field" do
+ @field.events.first.should_not == nil
+ end
+
+ it "should create the form event and then the field event" do
+ @field.events.first.id.should > @form.events.first.id
+ end
+
+ it "should not set batch_parent_id on the Form event" do
+ @form.events.first.batch_parent_id.should == nil
+ end
+
+ it "should set batch_parent_id on the Field event" do
+ @field.events.first.batch_parent_id.should == @form.events.first.id
+ end
+
+ it "should set the batch_size on the Form event to 2" do
+ @form.events.first.batch_size.should == 2
+ end
+
+ it "should set the batch_size on the Field event to 1" do
+ @field.events.first.batch_size.should == 1
+ end
+
+ it "should make the field event a child_batch_event" do
+ @form.events.first.child_batch_events.first.should == @field.events.first
+ end
+
+ describe "after destroying the parent resource" do
+ before(:each) do
+ @base_destory_event_count = Event.count(:conditions=>{:action=>'destroyed'})
+ @form.destroy
+ end
+
+ it "should create two new destroy events" do
+ (Event.count(:conditions=>{:action=>'destroyed'}) - @base_destory_event_count).should == 2
+ end
+
+ it "should create the form destroy event before the field destroy event" do
+ Event.find(:all,:order=>'id desc')[0].eventable_type.should == "Field"
+ Event.find(:all,:order=>'id desc')[1].eventable_type.should == "Form"
+ end
+
+ it "should not set batch_parent_id on the Form event" do
+ Event.find(:all,:order=>'id desc')[1].batch_parent_id.should == nil
+ end
+
+ it "should set batch_parent_id on the Field event to that of the Form event" do
+ Event.find(:all,:order=>'id desc')[0].batch_parent_id.should == Event.find(:all,:order=>'id desc')[1].id
+ end
+
+ it "should set the batch_size on the Form event to 2" do
+ Event.find(:all,:order=>'id desc')[1].batch_size.should == 2
+ end
+
+ it "should set the batch_size on the Field event to 1" do
+ Event.find(:all,:order=>'id desc')[0].batch_size.should == 1
+ end
+
+ it "should make the field event a child_batch_event" do
+ Event.find(:all,:order=>'id desc')[1].child_batch_events.first.should == Event.find(:all,:order=>'id desc')[0]
+ end
+ end
+ end
+
+ after(:each) do
+ Event.event_user = nil
+ end
+ end
+end
+
3  spec/db/database.yml
@@ -0,0 +1,3 @@
+sqlite3:
+ :adapter: sqlite3
+ :dbfile: vendor/plugins/acts_as_eventable/spec/db/acts_as_eventable.sqlite3.db
27 spec/db/schema.rb
@@ -0,0 +1,27 @@
+require File.join(File.dirname(__FILE__),'../../generators/acts_as_eventable_migration/templates/migration')
+
+ActiveRecord::Schema.define(:version => 1) do
+ ActsAsEventableMigration.up
+
+ create_table :users do |t|
+ t.string :username
+ t.timestamps
+ end
+
+ create_table :authors do |t|
+ t.string :username
+ t.timestamps
+ end
+
+ create_table :forms do |t|
+ t.string :title
+ t.timestamps
+ end
+
+ create_table :fields do |t|
+ t.integer :form_id
+ t.string :name
+ t.string :value
+ t.timestamps
+ end
+end
120 spec/event_spec.rb
@@ -0,0 +1,120 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+
+describe Event do
+ include UserSpecHelper
+
+ %w(create update publish).each do |action|
+ describe 'non destroy event' do
+ before(:each) do
+ @valid_event_attributes = {
+ :action => action,
+ :eventable_id => 1,
+ :eventable_type => 'Form',
+ :eventable_attributes => nil,
+ :user_id => 1
+ }
+ end
+
+ it "should create a new instance given valid attributes" do
+ Event.create!(@valid_event_attributes)
+ end
+
+ it "should be invalid without an action" do
+ Event.new(@valid_event_attributes.except(:action)).valid?.should == false
+ end
+
+ it "should be invalid without an eventable_id" do
+ Event.new(@valid_event_attributes.except(:eventable_id)).valid?.should == false
+ end
+
+ it "should be invalid without an eventable_type" do
+ Event.new(@valid_event_attributes.except(:eventable_type)).valid?.should == false
+ end
+
+ it "should be invalid without a user_id" do
+ Event.new(@valid_event_attributes.except(:user_id)).valid?.should == false
+ end
+ end
+ end
+
+ describe 'destroy event' do
+ before(:each) do
+ @valid_event_attributes = {
+ :action => 'destroyed',
+ :eventable_id => nil,
+ :eventable_type => 'Form',
+ :eventable_attributes => {:title=>'test form'},
+ :user_id => 1
+ }
+ end
+
+ it "should create a new instance given valid attributes" do
+ Event.create!(@valid_event_attributes)
+ end
+
+ it "should clear the eventable_id" do
+ event = Event.create!(@valid_event_attributes)
+ event.eventable_id.should == nil
+ end
+
+ it "should be valid without an eventable_id" do
+ Event.new(@valid_event_attributes.except(:eventable_id)).valid?.should == true
+ end
+
+ it "should be invalid without an eventable_type" do
+ Event.new(@valid_event_attributes.except(:eventable_type)).valid?.should == false
+ end
+
+ it "should be invalid without a user_id" do
+ Event.new(@valid_event_attributes.except(:user_id)).valid?.should == false
+ end
+
+ it "should be invalid without eventable_attributes" do
+ Event.new(@valid_event_attributes.except(:eventable_attributes)).valid?.should == false
+ end
+ end
+
+ describe "with standard user class name" do
+ before(:each) do
+ @user = create_valid_user
+
+ @valid_event_attributes = {
+ :action => 'created',
+ :eventable_id => 1,
+ :eventable_type => 'Form',
+ :eventable_attributes => nil,
+ :user => @user
+ }
+ end
+
+ it "should create a new instance given valid attributes" do
+ Event.create!(@valid_event_attributes)
+ end
+ end
+
+ describe "with non-standard user class name" do
+ include AuthorSpecHelper
+
+ before(:each) do
+ @author = create_valid_author
+
+ @valid_event_attributes = {
+ :action => 'created',
+ :eventable_id => 1,
+ :eventable_type => 'Form',
+ :eventable_attributes => nil,
+ :user => @author
+ }
+
+
+ Dependencies.remove_constant('Event') rescue Exception
+ ActsAsEventable::Options.event_belongs_to_user_options[:class_name] = 'Author'
+ require 'event'
+ end
+
+ it "should create a new instance given valid attributes" do
+ Event.create!(@valid_event_attributes)
+ end
+ end
+end
81 spec/spec_helper.rb
@@ -0,0 +1,81 @@
+begin
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
+rescue LoadError
+ puts "You need to install rspec in your base app"
+ exit
+end
+
+# Unload rails app load paths
+Dependencies.load_paths.reject! { |path| path =~ /\/app(\/|$)/ }
+Dependencies.load_once_paths.reject! { |path| path =~ /\/app(\/|$)/ }
+
+plugin_spec_dir = File.dirname(__FILE__)
+ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
+
+database = YAML::load(IO.read(plugin_spec_dir + "/db/database.yml"))[ENV["DB"] || "sqlite3"]
+
+# clear the database (this will only work with sqllite
+dbfile = database[:dbfile]
+File.delete(dbfile) if File.exist?(dbfile)
+
+ActiveRecord::Base.establish_connection(database)
+
+load(File.join(plugin_spec_dir, "db", "schema.rb"))
+
+# ensure all the models below aren't already loaded by the app
+%w(User Author Form Field).each do |klass|
+ Dependencies.remove_constant(klass) rescue Exception
+end
+
+class User < ActiveRecord::Base
+ validates_presence_of :username
+ validates_length_of :username, :maximum => 255, :allow_blank => true
+end
+
+class Author < ActiveRecord::Base
+ validates_presence_of :username
+ validates_length_of :username, :maximum => 255, :allow_blank => true
+end
+
+class Form < ActiveRecord::Base
+ validates_presence_of :title
+ validates_length_of :title, :maximum => 255, :allow_blank => true
+
+ has_many :fields, :dependent => :destroy
+end
+
+class Field < ActiveRecord::Base
+ belongs_to :form
+
+ validates_presence_of :name
+ validates_length_of :name, :maximum => 255, :allow_blank => true
+ validates_length_of :value, :maximum => 255, :allow_blank => true
+end
+
+module AuthorSpecHelper
+ def create_valid_author
+ Author.create!({:username=>"Username"})
+ end
+end
+
+module UserSpecHelper
+ def create_valid_user
+ User.create!({:username=>"Authorname"})
+ end
+end
+
+module FormSpecHelper
+ def valid_form_attributes
+ {:title=>"Form 1"}
+ end
+
+ def valid_field_attributes
+ {:name=>"Field 1", :value=>'Value 1'}
+ end
+end
+
+module EventSpecHelper
+ def valid_event_attributes
+ end
+end
+
4 tasks/acts_as_eventable_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :acts_as_eventable do
+# # Task goes here
+# end
1  uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
Please sign in to comment.
Something went wrong with that request. Please try again.