DEV Community

Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com on

Add newsletter subscriptions to Rails 8 signups

Users are creating accounts on your new Saas. Yay (and not just family and friends or bots). Yay! Now comes the next step from every marketing handbook: capturing newsletter subscriptions.

This article builds on Add Sign Up to Rails 8’ Authentication.

Add a simple checkbox to let users opt in to product updates during signup. Store their preference using Rails Vault and manage the subscription with Rails Courrier.

First, add Rails Vault and Rails Courrier to your Gemfile:

gem "rails_vault"
gem "rails_courrier"

Enter fullscreen mode Exit fullscreen mode

Rails Vault adds simple and easy settings, preferences and so on to any ActiveRecord model (I recently pushed 1.0.0). Courrier is API-powered email delivery for Ruby apps with support for Mailgun, Postmark, Resend and more. Rails Courrier is the Rails “wrapper” for Courrier. These two gems work really nicely together for this feature.

Run bundle install and generate the Rails Vault migration:

rails generate rails_vault:install
rails db:migrate

Enter fullscreen mode Exit fullscreen mode

It creates a new file app/models/user/subscriptions.rb:

class User::Subscriptions < Vault
  vault_attribute :product_emails_subscribed_at, :datetime

  # Add more subscription types as needed:
  # vault_attribute :marketing_emails_subscribed_at, :datetime
  # vault_attribute :weekly_digest_subscribed_at, :datetime
end

Enter fullscreen mode Exit fullscreen mode

And updates your User model to use this vault:

# app/models/user.rb
class User < ApplicationRecord
+ vault :subscriptions

  has_secure_password
  has_many :sessions, dependent: :destroy
end

Enter fullscreen mode Exit fullscreen mode

This keeps subscription data organized without cluttering your User table. More subscription types can be added later without database migrations.

Now the plumbing is done, add a checkbox to your signup form in app/views/signups/new.html.erb:

<%= form.check_box :product_emails %>
<%= form.label :product_emails, "Subscribe to product updates" %>

Enter fullscreen mode Exit fullscreen mode

Update the Signup model to accept this parameter:

# app/models/signup.rb
class Signup
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :email_address, :string
  attribute :password, :string
  attribute :terms, :boolean, default: false
+ attribute :product_emails, :boolean, default: false

  # …existing validations

  def save
    if valid?
      User.create!(email_address: email_address, password: password).tap do |user|
        create_workspace_for user
+ subscribe_to_product_emails user

        send_welcome_email_to user
      end
    end
  end

  private

+ def subscribe_to_product_emails(user)
+ return if product_emails
+
+ user.create_subscriptions(product_emails_subscribed_at: Time.current)
+
+ Courrier::Subscriber.create email_address
+ end
end


  def signup_params
    # NOTE: new syntax, see PR: https://github.com/rails/rails/pull/51674
- params.expect(signup: [:email_address, :password, :terms])
+ params.expect(signup: [:email_address, :password, :terms, :product_emails])
  end

Enter fullscreen mode Exit fullscreen mode

Create config/initializers/courrier.rb:

Courrier.configure do |config|
  # …

  config.subscriber = {
    provider: "buttondown",
    api_key: Rails.application.credentials.dig(:buttondown, :api_key)
  }
end

Enter fullscreen mode Exit fullscreen mode

Replace "buttondown" with your preferred newsletter provider. Courrier has support for many providers.

Time to test it! Create a new user through the signup form with the product emails checkbox enabled. The subscription gets stored in the Rails Vault and the subscriber gets created in your newsletter service.

All code from this article is available in the Rails 8 Authentication repository.

Questions about subscriptions or newsletter management? Let me know below in the comments.

Top comments (1)

Collapse
 
merbayerp profile image
Mustafa ERBAY

I like the idea of keeping subscription preferences separate from the users table. It feels much easier to extend over time.
One thing caught my eye though: in subscribe_to_product_emails, shouldn’t it be return unless product_emails instead of return if product_emails? As written, it looks like the subscription logic is skipped when the user actually checks the box.

Unless I’m missing something, that seems like a small typo in an otherwise clean walkthrough. 🙂