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:

“by

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:

“by gem ‘moist’

And then execute:

“sh $ bundle

Bring in the initializer and migrations:

“sh $ rails g moist:setup

And do the migrate:

“sh $ 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.

“by 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.

“lass 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.

“by class MoistSchedulerJob < ApplicationJob def perform ::Moist::Scheduler.run end end

5. Done!

All done. Some nice-to-haves:

“by class Cart has_moist_campaigns end

Gives you

“by @cart.moist_campaigns

“lass User acts_as_moist_user end

Gives you:

“by @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.