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