Rails 取消订阅的电子邮件 link
Rails Email with Unsubscribe link
我正在开发一个 Rails 4.2 应用程序,该应用程序具有人们注册的每周重复活动。他们将在每次活动前(每周一次)收到一封提醒邮件。我想单击一下取消订阅电子邮件 link。这似乎是一项常见的任务,但我目前还没有找到好的解决方案。我看到的一些说明是使用 MessageVerifier,它是 Rails 4.1 的新功能,不需要保存令牌字符串来与数据库中的进行比较。完成此操作的步骤是什么。我有一个用户模型和一个事件模型。电子邮件将发送给注册重复活动的注册用户。
一个非常好的选择可能是使用 Michael Hartl 的 Rails 教程应用程序。在 chapter 12 中,他实现了一个系统,用户可以在其中关注其他用户的微博(基本上是推文,twitter 风格)。您只需要设置模型验证(用户和事件模型)并实施关系模型和控制器。关系模型和控制器处理整个后续机制。本质上,控制器只有创建和删除操作,创建操作用于创建关系,销毁用于删除它。要处理取消订阅的情况,您可以简单地让 rails 在 ActionMailer 模板中呈现删除路径。上面的 link 为您提供了逐步说明,但如果您迷路了,请随时问我问题。
这是我提出的取消订阅 link 发送给订阅者的常规电子邮件的解决方案。它使用 MessageVerifier。
1。生成 user.id
的加密哈希
在我的事件控制器中,我有一个发送电子邮件的 send_notice 操作。我将为取消订阅创建一个变量 link 并将其传递给邮件程序。
# app/controller/events_controller.rb
def send_notice
...
@unsubscribe = Rails.application.message_verifier(:unsubscribe).generate(@user.id)
EventMailer.send_notice(@event, @user, @unsubscribe).deliver_later
end
这会获取用户 ID 并生成一个经过签名和编码的字符串变量@unsubscribe。消息验证器通过将用户 ID 与您的 secret_key_base(在文件 config/secrets.yml 中找到)以及您提供的消息名称(在本例中是我'我称它为 :unsubscribe 但它可以是任何名称)作为他们所说的盐,并且 运行 通过称为 SHA1 的算法。确保您的 secret_key_base 保持安全。使用环境变量来存储生产中的值。
在最后一行中,我们将@unsubscribe 变量与@event 和@user 变量一起传递给邮件程序。
2。将@unsubscribe 哈希变量添加到邮件
# app/mailers/event_mailer.rb
def send_notice(event, user, unsubscribe)
@event = event
@user = user
@unsubscribe = unsubscribe
mail(to: user.email, subject: "Event Info")
end
3。把退订link放在邮件里
# app/views/events_mailer/send_notice.html.erb
...
<%= link_to "Unsubscribe", settings_unsubscribe_url(id: @unsubscribe) %>.
注意添加的 (id: @unsubscribe) 参数。这会将编码后的用户 ID 附加到以 ? 开头的 URL 的末尾。在所谓的查询参数中。
4。添加路线
添加将用户带到取消订阅页面的路由。然后是他们提交退订时的另一条路线。
# config/routes.rb
get 'settings/unsubscribe'
patch 'settings/update'
5。向用户模型添加订阅字段
我选择向用户模型添加订阅布尔值 (true/false) 字段,但您可以通过多种不同的方式进行设置。 rails g migration AddSubscriptionToUsers subscription:boolean
.
6。控制器 - 从 URL
解码 user_id
我选择添加一个带有取消订阅和更新操作的设置控制器。生成控制器 rails g controller Settings unsubscribe
。
当用户单击电子邮件中的取消订阅 link 时,它将转到 url 并将编码的用户 ID 附加到问号后的 URL 作为查询参数。下面是 link 的示例:http://localhost:3000/settings/unsubscribe?id=BAhpEg%3D%3D--be9f8b9e64e13317bb0901d8725ce746b156b152。
取消订阅操作将使用 MessageVerifier 取消签名和解码 id 参数以获取实际用户 ID,并使用它来查找用户并将其分配给 @user 变量。
# app/controllers/settings_controller.rb
def unsubscribe
user = Rails.application.message_verifier(:unsubscribe).verify(params[:id])
@user = User.find(user)
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
flash[:notice] = 'Subscription Cancelled'
redirect_to root_url
else
flash[:alert] = 'There was a problem'
render :unsubscribe
end
end
private
def user_params
params.require(:user).permit(:subscription)
end
7。观看次数
添加取消订阅页面,其中包含用于取消订阅的表单。
# app/views/settings/unsubscribe.html.erb
<h4>Unsubscribe from Mysite Emails</h4>
<p>By unsubscribing, you will no longer receive email...</p>
<%= form_for(@user, url: settings_update_path(id: @user.id)) do |f| %>
<%= f.hidden_field(:subscription, value: false) %>
<%= f.submit 'Unsubscribe' %>
<%= link_to 'Cancel', root_url %>
<% end %>
您可以通过多种方式进行设置。在这里,我使用路由到 settings_update_path 的 form_for 助手,并添加了一个 id 参数:@user.id。当将表单作为查询参数发送时,这会将用户 ID 附加到 URL。 Update 操作将读取它以查找用户并将 Subscription 字段更新为 false。
我是这样做的:
class User < ApplicationRecord
has_many :unsubscribes
scope :unsubscribed, -> (list) { joins(:unsubscribes).where(unsubscribes: { list: list }) }
scope :subscribed, -> (list) { where.not(id: User.unsubscribed(list)) }
def subscribed?(list)
unsubscribes.where(list: list).none?
end
def unsubscribed?(list)
!subscribed?(list)
end
end
class Unsubscribe < ApplicationRecord
LISTS = %w[
message_mailer-messages_email
user_mailer-reset_password_email
event_mailer-summary_email
].freeze
belongs_to :user
validates :list,
presence: true,
uniqueness: {
scope: :user_id
},
inclusion: {
in: LISTS
}
end
class CreateUnsubscribes < ActiveRecord::Migration[6.1]
def change
create_table :unsubscribes do |t|
t.string :list, null: false
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :unsubscribes, %i[list user_id], unique: true
end
end
class UnsubscribesController < ApplicationController
before_action :load_user
helper_method :unsubscribe_url
helper_method :unsubscribes_url
def show
authorize :unsubscribe
@list = params[:id]
@unsubscribe = Unsubscribe.find_by(user: @user, list: params[:id])
end
def create
@unsubscribe = Unsubscribe.new(unsubscribe_params)
@unsubscribe.user = @user
authorize @unsubscribe
if @unsubscribe.save
redirect_to unsubscribe_url
else
redirect_to unsubscribe_url,
alert: @unsubscribe.errors.full_messages.to_sentence
end
end
def destroy
authorize :unsubscribe
@unsubscribe = Unsubscribe.find_by!(user: @user, list: params[:id])
@unsubscribe.destroy!
redirect_to unsubscribe_url
end
private
def load_user
@user = User.find_signed!(params[:user_id])
end
def unsubscribe_params
params.require(:unsubscribe).permit(:list)
end
def unsubscribe_url
if @unsubscribe
user_unsubscribe_url(user_id: @user.signed_id, id: @unsubscribe.list)
else
user_unsubscribe_url(user_id: @user.signed_id, id: @list)
end
end
def unsubscribes_url
user_unsubscribes_url(user_id: @user.signed_id)
end
end
# app/views/unsubscribes/show.html.slim
- title t(".lists.#{@list}")
- if @unsubscribe
p.text-center.text-green-600= t(".you_are_unsubscribed")
.text-center.mb-4
= button_to t(".subscribe"), unsubscribe_url, method: :delete
- else
p.text-center.text-green-600= t(".you_are_subscribed")
= form_for Unsubscribe.new, url: unsubscribes_url do |f|
= f.hidden_field :list, value: @list
p.text-center
= f.submit t(".unsubscribe")
# config/routes.rb
resources :users do
resources :unsubscribes
end
我正在开发一个 Rails 4.2 应用程序,该应用程序具有人们注册的每周重复活动。他们将在每次活动前(每周一次)收到一封提醒邮件。我想单击一下取消订阅电子邮件 link。这似乎是一项常见的任务,但我目前还没有找到好的解决方案。我看到的一些说明是使用 MessageVerifier,它是 Rails 4.1 的新功能,不需要保存令牌字符串来与数据库中的进行比较。完成此操作的步骤是什么。我有一个用户模型和一个事件模型。电子邮件将发送给注册重复活动的注册用户。
一个非常好的选择可能是使用 Michael Hartl 的 Rails 教程应用程序。在 chapter 12 中,他实现了一个系统,用户可以在其中关注其他用户的微博(基本上是推文,twitter 风格)。您只需要设置模型验证(用户和事件模型)并实施关系模型和控制器。关系模型和控制器处理整个后续机制。本质上,控制器只有创建和删除操作,创建操作用于创建关系,销毁用于删除它。要处理取消订阅的情况,您可以简单地让 rails 在 ActionMailer 模板中呈现删除路径。上面的 link 为您提供了逐步说明,但如果您迷路了,请随时问我问题。
这是我提出的取消订阅 link 发送给订阅者的常规电子邮件的解决方案。它使用 MessageVerifier。
1。生成 user.id
的加密哈希在我的事件控制器中,我有一个发送电子邮件的 send_notice 操作。我将为取消订阅创建一个变量 link 并将其传递给邮件程序。
# app/controller/events_controller.rb
def send_notice
...
@unsubscribe = Rails.application.message_verifier(:unsubscribe).generate(@user.id)
EventMailer.send_notice(@event, @user, @unsubscribe).deliver_later
end
这会获取用户 ID 并生成一个经过签名和编码的字符串变量@unsubscribe。消息验证器通过将用户 ID 与您的 secret_key_base(在文件 config/secrets.yml 中找到)以及您提供的消息名称(在本例中是我'我称它为 :unsubscribe 但它可以是任何名称)作为他们所说的盐,并且 运行 通过称为 SHA1 的算法。确保您的 secret_key_base 保持安全。使用环境变量来存储生产中的值。 在最后一行中,我们将@unsubscribe 变量与@event 和@user 变量一起传递给邮件程序。
2。将@unsubscribe 哈希变量添加到邮件
# app/mailers/event_mailer.rb
def send_notice(event, user, unsubscribe)
@event = event
@user = user
@unsubscribe = unsubscribe
mail(to: user.email, subject: "Event Info")
end
3。把退订link放在邮件里
# app/views/events_mailer/send_notice.html.erb
...
<%= link_to "Unsubscribe", settings_unsubscribe_url(id: @unsubscribe) %>.
注意添加的 (id: @unsubscribe) 参数。这会将编码后的用户 ID 附加到以 ? 开头的 URL 的末尾。在所谓的查询参数中。
4。添加路线
添加将用户带到取消订阅页面的路由。然后是他们提交退订时的另一条路线。
# config/routes.rb
get 'settings/unsubscribe'
patch 'settings/update'
5。向用户模型添加订阅字段
我选择向用户模型添加订阅布尔值 (true/false) 字段,但您可以通过多种不同的方式进行设置。 rails g migration AddSubscriptionToUsers subscription:boolean
.
6。控制器 - 从 URL
解码 user_id我选择添加一个带有取消订阅和更新操作的设置控制器。生成控制器 rails g controller Settings unsubscribe
。
当用户单击电子邮件中的取消订阅 link 时,它将转到 url 并将编码的用户 ID 附加到问号后的 URL 作为查询参数。下面是 link 的示例:http://localhost:3000/settings/unsubscribe?id=BAhpEg%3D%3D--be9f8b9e64e13317bb0901d8725ce746b156b152。
取消订阅操作将使用 MessageVerifier 取消签名和解码 id 参数以获取实际用户 ID,并使用它来查找用户并将其分配给 @user 变量。
# app/controllers/settings_controller.rb
def unsubscribe
user = Rails.application.message_verifier(:unsubscribe).verify(params[:id])
@user = User.find(user)
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
flash[:notice] = 'Subscription Cancelled'
redirect_to root_url
else
flash[:alert] = 'There was a problem'
render :unsubscribe
end
end
private
def user_params
params.require(:user).permit(:subscription)
end
7。观看次数
添加取消订阅页面,其中包含用于取消订阅的表单。
# app/views/settings/unsubscribe.html.erb
<h4>Unsubscribe from Mysite Emails</h4>
<p>By unsubscribing, you will no longer receive email...</p>
<%= form_for(@user, url: settings_update_path(id: @user.id)) do |f| %>
<%= f.hidden_field(:subscription, value: false) %>
<%= f.submit 'Unsubscribe' %>
<%= link_to 'Cancel', root_url %>
<% end %>
您可以通过多种方式进行设置。在这里,我使用路由到 settings_update_path 的 form_for 助手,并添加了一个 id 参数:@user.id。当将表单作为查询参数发送时,这会将用户 ID 附加到 URL。 Update 操作将读取它以查找用户并将 Subscription 字段更新为 false。
我是这样做的:
class User < ApplicationRecord
has_many :unsubscribes
scope :unsubscribed, -> (list) { joins(:unsubscribes).where(unsubscribes: { list: list }) }
scope :subscribed, -> (list) { where.not(id: User.unsubscribed(list)) }
def subscribed?(list)
unsubscribes.where(list: list).none?
end
def unsubscribed?(list)
!subscribed?(list)
end
end
class Unsubscribe < ApplicationRecord
LISTS = %w[
message_mailer-messages_email
user_mailer-reset_password_email
event_mailer-summary_email
].freeze
belongs_to :user
validates :list,
presence: true,
uniqueness: {
scope: :user_id
},
inclusion: {
in: LISTS
}
end
class CreateUnsubscribes < ActiveRecord::Migration[6.1]
def change
create_table :unsubscribes do |t|
t.string :list, null: false
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :unsubscribes, %i[list user_id], unique: true
end
end
class UnsubscribesController < ApplicationController
before_action :load_user
helper_method :unsubscribe_url
helper_method :unsubscribes_url
def show
authorize :unsubscribe
@list = params[:id]
@unsubscribe = Unsubscribe.find_by(user: @user, list: params[:id])
end
def create
@unsubscribe = Unsubscribe.new(unsubscribe_params)
@unsubscribe.user = @user
authorize @unsubscribe
if @unsubscribe.save
redirect_to unsubscribe_url
else
redirect_to unsubscribe_url,
alert: @unsubscribe.errors.full_messages.to_sentence
end
end
def destroy
authorize :unsubscribe
@unsubscribe = Unsubscribe.find_by!(user: @user, list: params[:id])
@unsubscribe.destroy!
redirect_to unsubscribe_url
end
private
def load_user
@user = User.find_signed!(params[:user_id])
end
def unsubscribe_params
params.require(:unsubscribe).permit(:list)
end
def unsubscribe_url
if @unsubscribe
user_unsubscribe_url(user_id: @user.signed_id, id: @unsubscribe.list)
else
user_unsubscribe_url(user_id: @user.signed_id, id: @list)
end
end
def unsubscribes_url
user_unsubscribes_url(user_id: @user.signed_id)
end
end
# app/views/unsubscribes/show.html.slim
- title t(".lists.#{@list}")
- if @unsubscribe
p.text-center.text-green-600= t(".you_are_unsubscribed")
.text-center.mb-4
= button_to t(".subscribe"), unsubscribe_url, method: :delete
- else
p.text-center.text-green-600= t(".you_are_subscribed")
= form_for Unsubscribe.new, url: unsubscribes_url do |f|
= f.hidden_field :list, value: @list
p.text-center
= f.submit t(".unsubscribe")
# config/routes.rb
resources :users do
resources :unsubscribes
end