Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/controllers/public_pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ def create
@email_address = EmailAddress.find_or_create_by(email: (params.dig(:email_address, :email) || params[:email]).strip.downcase)
return render :show, status: :bad_request unless @email_address.valid?

@subscription = Subscription.create_with(source: :signup).find_or_create_by(email_address: @email_address,
account: @account)
@subscription = Subscription.create_with(source: :signup).find_or_create_by_with_rescue(email_address: @email_address,
account: @account)

return redirect_to '/', notice: ALREADY_SUBSCRIBED_MESSAGE if @subscription.active?

Expand Down
4 changes: 2 additions & 2 deletions app/jobs/subscribers_import_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ def import(subscribers_import)
email_address = EmailAddress.find_or_create_by(email: email)

Subscription.create_with(source: :import, subscribers_import: subscribers_import, verified_at: Time.zone.now) \
.find_or_create_by(email_address: email_address,
account: account)
.find_or_create_by_with_rescue(email_address: email_address,
account: account)
end
end
end
5 changes: 2 additions & 3 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,9 @@ def subscribe_to_updates
updates = Account.find_by(slug: 'updates')
return if updates.blank?

# Ok if this fails
# Ok if this fails - use rescue helper to handle race conditions
Subscription.create_with(source: :signup, verified_at: Time.zone.now) \
.where(account: updates, email_address: EmailAddress.find_or_create_by(email: email)) \
.first_or_create
.find_or_create_by_with_rescue(account: updates, email_address: EmailAddress.find_or_create_by(email: email))
end

def unsubscribe_from_updates
Expand Down
9 changes: 9 additions & 0 deletions app/models/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ class Subscription < ApplicationRecord

enum source: { signup: 0, invite: 1, import: 2 }, _prefix: true
validates :source, presence: true
validates :email_address_id, uniqueness: { scope: :account_id, message: 'is already subscribed to this account' }

# Handle race condition: if DB constraint fires despite find_or_create_by,
# find the existing record instead of raising
def self.find_or_create_by_with_rescue(attributes, &block)
find_or_create_by(attributes, &block)
rescue ActiveRecord::RecordNotUnique
find_by!(attributes)
end

def active?
!!verified_at && !unsubscribed_at
Expand Down