Skip to content

Instantly share code, notes, and snippets.

@jacortinas
Created December 13, 2012 16:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacortinas/4277777 to your computer and use it in GitHub Desktop.
Save jacortinas/4277777 to your computer and use it in GitHub Desktop.
class InvitationRequest
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
include ActiveModel::Serializers::JSON
attr_reader :email, :url
attr_writer :clock, :invitation_class, :mailer
validates :email, presence: true
def self.for attributes
req = new attributes
req.fulfill if req.valid? && !req.fulfilled?
req
end
def initialize attributes = {}
@email = attributes[:email]
@url = attributes[:url]
@clock = Time
@invitation_class = Invitation
@mailer = InvitationMailer
end
def fulfill
@mailer.deliver_request_confirmation invitation
end
def fulfilled?
invitation.persisted?
end
def invitation
@invitation ||= find_invitation || create_invitation
end
def attributes
{ email: email, url: url, fulfilled?: fulfilled? }
end
def persisted?
false
end
private
def find_invitation
@invitation_class.find_by_email email
end
def create_invitation
@invitation_class.create email: email, url: url, requested_at: @clock.now.utc
end
end
class InvitationRequestSerializer < ActiveModel::Serializer
attributes :email, :url, :fulfilled?
end
require 'spec_helper'
describe InvitationRequest do
context 'when fulfilling for some attributes' do
it 'does not fulfill the request if not valid' do
req = double(:invitation_request, valid?: false)
InvitationRequest.stub(:new).and_return req
req.should_not_receive :fulfill
InvitationRequest.for email: 'test@test.com', url: 'test.com'
end
it 'does not fulfill the request if already fulfilled' do
req = double(:invitation_request, valid?: true, fulfilled?: true)
InvitationRequest.stub(:new).and_return req
req.should_not_receive :fulfill
InvitationRequest.for email: 'test@test.com', url: 'test.com'
end
end
it 'requires an email' do
expect(InvitationRequest.new).to have(1).error_on :email
end
it 'sets the email from initializing attributes' do
req = InvitationRequest.new email: 'test@test.com'
expect(req.email).to eq 'test@test.com'
end
it 'sets the url from initializing attributes' do
req = InvitationRequest.new url: 'test.com'
expect(req.url).to eq 'test.com'
end
it 'deliver a confirmation when fulfilled' do
req = InvitationRequest.new
mailer = double(:mailer).as_null_object
req.mailer = mailer
req.stub(:invitation).and_return 'fake invite'
mailer.should_receive(:deliver_request_confirmation).with 'fake invite'
req.fulfill
end
it 'is fulfilled if an invitation has already been created' do
req = InvitationRequest.new
invitation = double :invitation, persisted?: true
req.stub(:invitation).and_return invitation
expect(req).to be_fulfilled
end
context 'when fulfilled' do
it 'finds an invitation' do
req = InvitationRequest.new email: 'test@test.com'
cls = double :invitation_class
req.invitation_class = cls
cls.should_receive(:find_by_email).with('test@test.com').and_return 'an invitation'
expect(req.invitation).to eq 'an invitation'
end
end
context 'when not fulfilled' do
it 'creates an invitation' do
req = InvitationRequest.new email: 'test@test.com', url: 'test.com'
cls = double :invitation_class
clock = double :time
clock.stub_chain('now.utc').and_return Time.new(1970, 1, 1)
cls.stub(:find_by_email).and_return nil
cls.should_receive(:create).with(
hash_including({
email: 'test@test.com',
url: 'test.com',
requested_at: Time.new(1970, 1, 1)
})
).and_return 'an invitation'
req.invitation_class = cls
req.clock = clock
expect(req.invitation).to eq 'an invitation'
end
end
end
class InvitationRequestsController < ApplicationController
respond_to :json, only: :create
def new
@invitation_request = InvitationRequest.new
end
def create
respond_with InvitationRequest.for(valid_params), location: root_url
end
private
def valid_params
params.fetch(:invitation_request).slice(:email, :url)
end
end
require 'spec_helper'
describe InvitationRequestsController do
describe 'GET new' do
it 'assigns a new invitation request' do
get:new
expect(assigns(:invitation_request)).to be_instance_of InvitationRequest
end
it 'renders the new template' do
get :new
expect(response).to render_template 'new'
end
end
describe 'POST create' do
context 'when the invitation request has errors' do
it 'renders the errors as json' do
post :create, invitation_request: {}, format: :json
expect(response.body).to match /^{\"errors\":/
end
end
context 'when the invitation request is valid' do
it 'renders the invitation request' do
req = InvitationRequest.new email: 'test@test.com'
InvitationRequest.stub(:for).and_return req
post :create, invitation_request: { email: 'test@test.com' }, format: :json
expect(response.body).to eq req.to_json
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment