Created
August 1, 2012 22:18
-
-
Save kidpollo/3231215 to your computer and use it in GitHub Desktop.
Generic pattern for handling account trial states and notifications
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tn = TrialNotification.new(@account, Notifier) | |
tn.assm_current_state | |
# :trial | |
tn.send_first_notification! | |
tn.assm_current_state | |
# :first_notification_sent | |
tn.send_second_notification! | |
tn.assm_current_state | |
# :second_notification_sent | |
tn.send_third_notification! | |
tn.assm_current_state | |
# :third_notification_sent | |
tn.payment_information_provided! | |
tn.assm_current_state | |
# :converted_to_paying |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TrialNotification | |
include AASM | |
aasm_initial_state :trial | |
aasm_state :trial | |
aasm_state :first_notification_sent, :enter => :deliver_first_notification | |
aasm_state :second_notification_sent, :enter => :deliver_second_notification | |
aasm_state :third_notification_sent, :enter => :deliver_third_notification | |
aasm_state :trial_period_ended | |
aasm_state :converted_to_paying | |
aasm_event(:send_first_notification) do | |
transitions(:to => :first_notification_sent, :from => [:trial]) | |
end | |
aasm_event(:send_second_notification) do | |
transitions(:to => :second_notification_sent, :from => [:first_notification_sent]) | |
end | |
aasm_event(:send_third_notification) do | |
transitions(:to => :third_notification_sent, :from => [:second_notification_sent]) | |
end | |
aasm_event(:no_payment_info_provided) do | |
transitions(:to => :trial_period_ended, :from => [:third_notification_sent]) | |
end | |
aasm_event(:payment_information_provided) do | |
transitions(:to => :converted_to_paying, :from => [:new, :first_notification_sent, | |
:second_notification_sent, | |
:third_notification_sent]) | |
end | |
def initialize(persister, notifier) | |
@persister = persister | |
@notifier = notifier | |
end | |
private | |
def aasm_read_state | |
state = @persister.trial_notification_state | |
if state | |
state.to_sym | |
else | |
:trial | |
end | |
end | |
def aasm_write_state(state) | |
# persist ignoring callbacks and validations to | |
# avoid dealing with active_record madness | |
if ::ActiveRecord::VERSION::MAJOR <= 2 && ::ActiveRecord::VERSION::MINOR > 0 | |
@persister.trial_notification_state = state.to_s | |
@persister.send(:update_without_callbacks) | |
elsif ::ActiveRecord::VERSION::MINOR > 0 | |
@persister.update_column(:trial_notification_state, state.to_s) | |
end | |
end | |
def deliver_first_notification | |
@notifier.deliver_first_notification | |
end | |
def deliver_second_notification | |
@notifier.deliver_second_notification | |
end | |
def deliver_third_notification | |
@notifier.deliver_third_notification | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_fast_helper' | |
require 'aasm' | |
require 'app/models/trial_notification' | |
describe TrialNotification do | |
before do | |
@persister = Object.new | |
@notifier = Object.new | |
@trial_notification = TrialNotification.new(@persister,@notifier) | |
#dont worry about persistanse | |
stub(@trial_notification).aasm_write_state {true} | |
end | |
describe "initial state" do | |
it "should default to :trial if false" do | |
stub(@persister).trial_notification_state {false} | |
@trial_notification.aasm_current_state.should == :trial | |
end | |
it "should default to :trial if null" do | |
stub(@persister).trial_notification_state {nil} | |
@trial_notification.aasm_current_state.should == :trial | |
end | |
it "should not allow other states" do | |
stub(@persister).trial_notification_state {:any_other_state} | |
lambda{@trial_notification.send_first_notification!}.should raise_error(AASM::UndefinedState) | |
end | |
end | |
describe 'transitions' do | |
it 'should transition from :trial to :first_notification_sent' do | |
stub(@persister).trial_notification_state {:trial} | |
mock(@notifier).deliver_first_notification {true} | |
@trial_notification.send_first_notification!.should be_true | |
end | |
it 'should transition from :first_notification_sent to :second_notification_sent' do | |
stub(@persister).trial_notification_state {:first_notification_sent} | |
mock(@notifier).deliver_second_notification {true} | |
@trial_notification.send_second_notification!.should be_true | |
end | |
it 'should transition from :second_notification_sent to :third_notification_sent' do | |
stub(@persister).trial_notification_state {:second_notification_sent} | |
mock(@notifier).deliver_third_notification {true} | |
@trial_notification.send_third_notification!.should be_true | |
end | |
it 'should transition from :third_notification_sent to :trial_period_ended' do | |
stub(@persister).trial_notification_state {:third_notification_sent} | |
@trial_notification.no_payment_info_provided!.should be_true | |
end | |
[:trial,:first_notification_sent,:second_notification_sent,:third_notification_sent].each do |state| | |
it "should be able to transition from #{state} to :converted_to_paying" do | |
stub(@persister).trial_notification_state {state} | |
lambda{@trial_notification.converted_to_paying!}.should be_true | |
end | |
end | |
#pretty much the same logic for sencond and third states so its not going to be tested | |
[:first_notification_sent,:second_notification_sent,:third_notification_sent,:trial_period_ended,:converted_to_paying].each do |state| | |
it "should not transition from any other but #{state} to :first_notification_sent" do | |
stub(@persister).trial_notification_state {state} | |
lambda{@trial_notification.send_first_notification!}.should raise_error(AASM::InvalidTransition) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment