From f0e1a2890e163dbd5215a8d9982fbd266dc5922e Mon Sep 17 00:00:00 2001 From: Bill Niblock Date: Fri, 24 Jan 2025 14:11:47 -0500 Subject: [PATCH] Next dump --- app/controllers/unsubscribes_controller.rb | 15 +++++++++++++++ app/mailers/product_mailer.rb | 11 +++++++++++ app/models/product.rb | 2 +- app/models/product/notifications.rb | 18 ++++++++++++++++++ app/models/subscriber.rb | 1 + app/views/product_mailer/in_stock.html.erb | 7 +++++++ app/views/product_mailer/in_stock.text.erb | 6 ++++++ app/views/products/_inventory.html.erb | 11 +++++++++++ app/views/products/show.html.erb | 2 ++ config/routes.rb | 1 + .../mailers/previews/product_mailer_preview.rb | 7 +++++++ test/mailers/product_mailer_test.rb | 11 +++++++++++ 12 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/controllers/unsubscribes_controller.rb create mode 100644 app/mailers/product_mailer.rb create mode 100644 app/models/product/notifications.rb create mode 100644 app/views/product_mailer/in_stock.html.erb create mode 100644 app/views/product_mailer/in_stock.text.erb create mode 100644 app/views/products/_inventory.html.erb create mode 100644 test/mailers/previews/product_mailer_preview.rb create mode 100644 test/mailers/product_mailer_test.rb diff --git a/app/controllers/unsubscribes_controller.rb b/app/controllers/unsubscribes_controller.rb new file mode 100644 index 0000000..3b2aa56 --- /dev/null +++ b/app/controllers/unsubscribes_controller.rb @@ -0,0 +1,15 @@ +class UnsubscribesController < ApplicationController + allow_unauthenticated_access + before_action :set_subscriber + + def show + @subscriber.destroy + redirect_to root_path, notice: "Unsubscribed successfully." + end + + private + + def set_subscriber + @subscriber = Subscriber.find_by_token_for(:unsubscribe, params[:token]) + end +end diff --git a/app/mailers/product_mailer.rb b/app/mailers/product_mailer.rb new file mode 100644 index 0000000..82c6562 --- /dev/null +++ b/app/mailers/product_mailer.rb @@ -0,0 +1,11 @@ +class ProductMailer < ApplicationMailer + # Subject can be set in your I18n file at config/locales/en.yml + # with the following lookup: + # + # en.product_mailer.in_stock.subject + # + def in_stock + @product = params[:product] + mail to: params[:subscriber].email + end +end diff --git a/app/models/product.rb b/app/models/product.rb index a182079..1771221 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,5 +1,5 @@ class Product < ApplicationRecord - has_many :subscribers, dependent: :destroy + include Notifications has_one_attached :featured_image has_rich_text :description diff --git a/app/models/product/notifications.rb b/app/models/product/notifications.rb new file mode 100644 index 0000000..60c54df --- /dev/null +++ b/app/models/product/notifications.rb @@ -0,0 +1,18 @@ +module Product::Notifications + extend ActiveSupport::Concern + + included do + has_many :subscribers, dependent: :destroy + after_update_commit :notify_subscribers, if: :back_in_stock? + + def back_in_stock? + inventory_count_previously_was.zero? && inventory_count > 0 + end + + def notify_subscribers + subscribers.each do |sub| + ProductMailer.with(product: self, subscriber: sub).in_stock.deliver_later + end + end + end +end diff --git a/app/models/subscriber.rb b/app/models/subscriber.rb index cb8c5c4..a6303f8 100644 --- a/app/models/subscriber.rb +++ b/app/models/subscriber.rb @@ -1,3 +1,4 @@ class Subscriber < ApplicationRecord belongs_to :product + generates_token_for :unsubscribe end diff --git a/app/views/product_mailer/in_stock.html.erb b/app/views/product_mailer/in_stock.html.erb new file mode 100644 index 0000000..3b7944d --- /dev/null +++ b/app/views/product_mailer/in_stock.html.erb @@ -0,0 +1,7 @@ +

Good News!

+ +

+ <%= link_to @product.name, product_url(@product) %> is back in stock! +

+ +<%= link_to "Unsubscribe", unsubscribe_url(token: params[:subscriber].generate_token_for(:unsubscribe) %> diff --git a/app/views/product_mailer/in_stock.text.erb b/app/views/product_mailer/in_stock.text.erb new file mode 100644 index 0000000..fdb894d --- /dev/null +++ b/app/views/product_mailer/in_stock.text.erb @@ -0,0 +1,6 @@ +Good News! + +<%= @product.name %> is back in stock! +<%= product_url(@product) %> + +Unsubscribe: <%= unsubscribe_url(token: params[:subscriber].generate_token_for(:unsubscribe) %> diff --git a/app/views/products/_inventory.html.erb b/app/views/products/_inventory.html.erb new file mode 100644 index 0000000..4d67bf0 --- /dev/null +++ b/app/views/products/_inventory.html.erb @@ -0,0 +1,11 @@ +<% if product.inventory_count? %> +

<%= product.inventory_count %> in stock

+<% else %> +

Out of Stock

+

Notify me when more is stocked:

+ + <%= form_with model: [product, Subscriber.new] do |form| %> + <%= form.email_field :email, placeholder: "you@example.com", required: true %> + <%= form.submit %> + <% end %> +<% end %> diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index a81f657..f2aab3b 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -5,6 +5,8 @@ <%= @product.description %> <% end %> +<%= render "inventory", product: @product %> + <% if authenticated? %> <%= link_to "Edit", edit_product_path(@product) %> <%= button_to "Delete", @product, method: :delete, diff --git a/config/routes.rb b/config/routes.rb index 54b8c1e..3b6bbca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ Rails.application.routes.draw do resource :session resources :passwords, param: :token + resources :unsubscribe, only: [ :show ] # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html resources :products do resources :subscribers, only: [ :create ] diff --git a/test/mailers/previews/product_mailer_preview.rb b/test/mailers/previews/product_mailer_preview.rb new file mode 100644 index 0000000..c352155 --- /dev/null +++ b/test/mailers/previews/product_mailer_preview.rb @@ -0,0 +1,7 @@ +# Preview all emails at http://localhost:3000/rails/mailers/product_mailer +class ProductMailerPreview < ActionMailer::Preview + # Preview this email at http://localhost:3000/rails/mailers/product_mailer/in_stock + def in_stock + ProductMailer.in_stock + end +end diff --git a/test/mailers/product_mailer_test.rb b/test/mailers/product_mailer_test.rb new file mode 100644 index 0000000..e64bd04 --- /dev/null +++ b/test/mailers/product_mailer_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ProductMailerTest < ActionMailer::TestCase + test "in_stock" do + mail = ProductMailer.in_stock + assert_equal "In stock", mail.subject + assert_equal [ "to@example.org" ], mail.to + assert_equal [ "from@example.com" ], mail.from + assert_match "Hi", mail.body.encoded + end +end