Moist
Drip engine, for Ruby on Rails.
Why the name?
Because drip
was taken and moist
was available.
There is also a measurable amount of people who hate the word moist. Which results in a poor adoption strategy. In turn, fewer stars. Conclusion: recruiters won't bother me?
Goals?
Should you use this?
Maybe, here's the gist:
# Create a campaign:
::Moist::Campaign.create(name: "Abandoned cart", slug: "cart")
# Add `moist` to mailer:
class AbandonedCartMailer < ActionMailer::Base
moist :you_forgot_something, campaign: :cart, step: 1, delay: 1.hour
def you_forgot_something(cart)
# ...
end
moist :selling_out_soon, campaign: :cart, step: 2, delay: 4.hours
def selling_out_soon(cart)
# ...
end
end
# Add to a drip campaign:
::Moist::Campaign.subscribe(cart, user: cart.user).to(:cart)
# Remove from a drip campaign:
::Moist::Campaign.unsubscribe(cart, user: cart.user).from(:cart)
Installation
Add this line to your application's Gemfile:
gem 'moist'
And then execute:
$ bundle
Bring in the initializer and migrations:
$ rails g moist:setup
And do the migrate:
$ rails db:migrate
Setup Moist
How to use Moist
to create an abandoned cart drip campaign.
1. First, create a Moist::Campaign
.
Moist::Campaign.create(name: "Abandoned cart
, slug: "cart")`
The slug
used here will be referenced later. Note it.
2. Use moist
in your mailer to create steps.
You'll need to define @moist_subscriber
and @moist_user
in each mailer. This tells Moist what Moist::Mailing
to
associate with the mailer.
class AbandonedCartMailer < ActionMailer::Base
moist :you_forgot_something, campaign: :cart, step: 1, delay: 1.hour
def you_forgot_something(cart)
@cart = cart
@moist_subscriber = cart
@moist_user = cart.user
mail(subject: "You forgot something...", to: @cart.user.email)
end
moist :free_shipping_if_you_order_now, campaign: :cart, step: 2, delay: 2.days
def free_shipping_if_you_order_now(cart)
@cart = cart
@moist_subscriber = cart
@moist_user = cart.user
mail(subject: "Free shipping? Yep. Complete your purchase right meow!", to: @cart.user.email)
end
end
In these mailer methods, make sure you assign a @moist_subscriber
and a @moist_user
. If you don't, bad things will happen.
3. Add @cart
to the campaign
Probably a background job.
class AbandonedCartJob < ApplicationJob
TIME_TO_LIVE = 1.hour
def perform
Cart.where(checked_out: false).where('updated_at < ?', TIME_TO_LIVE.ago).each do |cart|
::Moist::Campaign.subscribe(cart, user: cart.user).to(:cart)
end
end
end
4. Run the scheduler
This manages the mailers and the drips.
class MoistSchedulerJob < ApplicationJob
def perform
::Moist::Scheduler.run
end
end
5. Done!
All done. Some nice-to-haves:
class Cart
has_moist_campaigns
end
Gives you
@cart.moist_campaigns
class User
acts_as_moist_user
end
Gives you:
@user.moist_subscriptions
Data models
Three core concepts:
Campaign
This is just an object for reference.
CampaignSubscriber
This joins a Campaign
to a subscriber
(polymorphic anything), and a user
. In theory, a user
can have many moist_campaign_subscribers
,
which would relate it to objects that belong to a user
.
This is useful if you have an Order
object and a Subscription
object that you want to create different campaigns for.
Mailing
Takes your ActionMailer moist
calls and turns them into database records. They have send_at
and sent_at
columns,
in addition to information about the mailers they belong to.
Contributing
Just do it.
Todo
- Logo, duh
- Web UI examples
- Ability to pause a campaign?
- Conversion stuff
- Handle updating steps
- Use block for handling
delay
License
The gem is available as open source under the terms of the MIT License.