For proper attribution, I'll note that a whole lot of the code in this post came directly from or was inspired by Multiple Table Inheritance with ActiveRecord.
In this post, I want to show how a validation defined in the ActsAsEvent module can be enforced in any class that includes ActsAsEvent.
Delegate Validation to EventBase
In my EventBase class definition, I have a validation for description:
class EventBase < ActiveRecord::Base # ========================================================================================== # Validations # ========================================================================================== validates_presence_of :description # ========================================================================================== # Associations # ========================================================================================== belongs_to :recur_rule, dependent: :destroy belongs_to :eventable, polymorphic: true, dependent: :destroy end
Getting classes that act_as_event to respect this validation is actually pretty straight forward. I updated my ActsAsEvent module like this:
module ActsAsEvent
def acts_as_event
class_eval do
include InstanceMethods
extend ClassMethods
has_one :event_base, as: :eventable, :autosave => true, :dependent => :destroy
validate :validate_event_base_properties
alias_method_chain :event_base, :build
end
end
module InstanceMethods
def event_base_with_build
event_base_without_build || build_event_base
end
def validate_event_base_properties
unless event_base.valid?
event_base.errors.each do |attr, message|
errors.add(attr, message)
end
end
end
end # InstanceMethods
module ClassMethods
end # ClassMethods
end
ActiveRecord::Base.extend ActsAsEvent
Within the class_eval block, I added validate :validate_event_base_properties. This causes validate_event_base_properties to be called during an attempt to save. Then, I added the validate_event_base_properties instance method. Now, when the composing class (Event or Trip) tries to save, the EventBase validations are called (and enforced).
Running the Test
So, I have a test from my previous post that failed:
require 'spec_helper'
describe Trip do
describe "responds to" do
end
describe "functions properly" do
it " - saves EventBase correctly" do
tcount_before = Trip.find(:all).count
ebcount_before = EventBase.find(:all).count
@t = Trip.create
tid = @t.id
@t.respond_to?("event_base").should be_true
@t.save.should be_false
@t.event_base.description = "test description"
@t.save.should be_true
@dbt = Trip.find(@t.id)
@dbt.event_base.description.should == "test description"
Trip.find(:all).count.should == tcount_before + 1
EventBase.find(:all).count.should == ebcount_before + 1
@dbt.destroy
Trip.find(:all).count.should == tcount_before
EventBase.find(:all).count.should == ebcount_before
end
end
end
Now, when I run:
$ rspec trip_spec.rb --format documentation
I get:
Trip functions properly - saves EventBase correctly Finished in 0.48657 seconds 1 example, 0 failures
Success! @t.save.should be_false now passes because the save fails (because description is not set). Then, when description is set, @t.save.should be_true now passes.
Next:
No comments:
Post a Comment