这是使用spree_frontend的原始文章here的重构版本。为了能够跟随,请花2-3分钟阅读。我称之为V1,使用了过时的Spree Commerce版本。 V2(此帖子)现在使用Spree v4.5.x使用spree_backend
Gem。
我已经更新了StockItemsControllerDecorator
# https://github.com/spree/spree_backend/blob/main/app/controllers/spree/admin/stock_items_controller.rb
module Spree
module Admin
module StockItemsControllerDecorator
# renamed from NotifyCustomersHelper
include NotifyCustomers
def self.prepended(base)
base.before_action :process_notifiees_on_stock_item, only: :update
# We have not taken into account should stock_movement.save fails.
# see https://github.com/spree/spree_backend/blob/main/app/controllers/spree/admin/stock_items_controller.rb#L13
base.before_action :process_notifiees_on_stock_movement, only: :create
# We don't need to track when deleted as the "track Inventory" can be checked when deleted.
# For this, look at Spree::Admin::VariantsIncludingMasterController#update
# base.before_action :notify_notifiees, only: :destroy
end
end
end
end
::Spree::Admin::StockItemsController.prepend Spree::Admin::StockItemsControllerDecorator if ::Spree::Admin::StockItemsController.included_modules.exclude?(Spree::Admin::StockItemsControllerDecorator)
variantsincludingmasterControllerDecorator也进行了重构,因为我们只在不再跟踪库存时才发送电子邮件:
module Spree
module Admin
module VariantsIncludingMasterControllerDecorator
include NotifyCustomers
def self.prepended(base)
# Defined in NotifyCustomers. Continue reading...
base.before_action :notify_notifiees, only: :update
end
end
end
end
::Spree::Admin::VariantsIncludingMasterController.prepend Spree::Admin::VariantsIncludingMasterControllerDecorator if ::Spree::Admin::VariantsIncludingMasterController.included_modules.exclude?(Spree::Admin::VariantsIncludingMasterControllerDecorator)
我还重构了NotifyCustomers
,而是寻找变体而不是产品:
module NotifyCustomers
private
# We've made the executive decision by not keeping stocks.
# Alert all customers that the product is available to purchase.
def notify_notifiees
variant_id = params[:id]
not_tracking = !ActiveRecord::Type::Boolean.new.cast(
params[:variant][:track_inventory]
)
not_tracking && email_all_notifiees(variant_id)
end
def process_notifiees_on_stock_movement
quantity = params[:stock_movement][:quantity].to_i
variant_id = params[:variant_id]
unless quantity.zero?
email_all_notifiees(variant_id)
end
end
def email_all_notifiees(variant_id)
notifiees = lookup_notifiees_by(variant_id)
send_notification_email(notifiees)
# We said we'd delete their email address
notifiees.destroy_all
end
def process_notifiees_on_stock_item
# Backorderable: boolean
# stock_item.backorderable
# Number of items in stock: integer
# stock_item.count_on_hand
unless stock_item.count_on_hand.zero?
variant_id = stock_item.variant.id
email_all_notifiees(variant_id)
end
end
def lookup_notifiees_by(variant_id)
Spree::VariantNotification.where(variant_id: variant_id)
end
def send_notification_email(notifiees)
if notifiees.present?
emails_to_send = notifiees.pluck(:email)
puts "---- SENDING EMAIL TO #{emails_to_send.length} email addresses (plural for now)"
# Now send the email
# You'll need to implement a mailer for this
end
end
end
迁移文件也已更新(我正在一个新项目中进行此操作):
class CreateSpreeVariantNotifications < ActiveRecord::Migration[7.0]
def change
create_table :spree_variant_notifications do |t|
t.references :user
t.references :variant, null: false
t.string :email, null: false
t.timestamps
end
end
end
更新的模型:
module Spree
class VariantNotification < ApplicationRecord
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
# Optional as a user doesnt have to be signed in
belongs_to :user, class_name: 'Spree::User', optional: true
belongs_to :variant, class_name: 'Spree::Variant'
end
end
module Spree
module VariantDecorator
def self.prepended(base)
base.has_many :notifications, class_name: 'Spree::VariantNotification', foreign_key: 'variant_id', dependent: :destroy
end
end
end
::Spree::Variant.prepend Spree::VariantDecorator if ::Spree::Variant.included_modules.exclude?(Spree::VariantDecorator)
也将电子邮件处理到我们的数据库中的地方:
module Spree
# Though belongs to a variant, we'll keep this for the product
module Products
class NotifyController < Spree::StoreController
before_action :set_variant
include ActionView::Helpers::TextHelper
# Does not uses a layout
layout false
def notify_me
email = strip_tags(notify_params[:email])
@notif = @variant.notifications.find_or_create_by(email: email) do |perm|
# user_id can be null
perm.user_id = spree_current_user&.id || notify_params[:user_id]
end
respond_to do |format|
if @notif.save
format.turbo_stream
else
format.html { redirect_to spree.product_path(@variant.product), alert: "Something went wrong", status: 422 }
end
end
end
private
def notify_params
params.fetch(:product_notification, {}).permit(:email)
end
def set_variant
@variant = Spree::Variant.find_by(id: params[:variant_id])
unless @variant.present?
redirect_to root_path
end
end
end
end
end
# Route updated to:
post '/products/:variant_id/notify', to: 'products/notify#notify_me', as: 'variant_notify'
_notify_me_when_available.html
,在_cart_form
内部,但也更新了订单表格外:
<%= form_with(
scope: :product_notification,
url: spree.variant_notify_path(variant),
data: {
controller: "reset-form",
action: "turbo:submit-end->reset-form#reset"
},
id: dom_id(variant, :notify)) do |form| %>
<%= form.label :email, "Notify me when in stock" %>
<%= form.email_field :email, class: 'spree-flat-input', placeholder: "Enter your email address", required: true %>
<%= form.submit "Notify me", class: "btn btn-primary w-100 text-uppercase font-weight-bold mt-2" %>
<p class="mt-2 text-sm">After this notification, your email address will be deleted and not used again.</p>
<% end %>
我在这个新项目中使用了涡轮增压器。提交表单时,我清除了输入字段,并且在成功时,我会用部分(spree/shared/_variant_notify_success
)更新DOM:
<div class="p-3 text-center bg-green-600 text-white sm:text-base text-sm">
<p>Great! We'll send you a one-time email when item becomes available.</p>
</div>
使用..
<%= turbo_stream.replace dom_id(@variant, :notify) do %>
<%= render "spree/shared/variant_notify_success" %>
<% end %>
...外订单表格:
<%# Outside order form %>
<% unless is_product_available_in_currency && @product.can_supply? %>
<%= render 'spree/shared/notify_me_when_available', variant: default_variant %>
<% end %>
如果变体缺货,则需要其他工作来显示/隐藏通知表格。我的示例只会在产品无法提供时显示通知表格。
Spree Frontend在SEED here上为.product-variants-variant-values-radio
提供了一个活动lister。您可以将逻辑放在那里显示/隐藏通知表格。这是逻辑:
在您的单击事件中,OPTION_VALUE_SELECTOR
(在您自己的js
文件中或使用刺激):
使用选定的variant_id
,将data-variants
的数据从购物车中解析。例如,在data-variants
的数组中,使用variants.find(o.id == variant_id).purchasable
检查该变体是否为purchasable
。基于True或fals,显示/隐藏通知表格。我从here获得purchasable
。
现在应该全部。 At the time of this post, I have not implement show/hide when an option is selected. Live demo here。