ruby-on-rails - 在 Rails 服务中处理数据的最佳方式
问题描述
我有一个提醒服务,它接受一些“更改请求”,然后将它们发送到工作队列以在以后执行。每个“更改请求”可以有“十分钟前”提醒和或“一小时后提醒”。未来还会有不同类型的提醒。
我正在寻找最优雅的红宝石处理方式,并将每个提醒发送给工人很多 if 语句感觉不对,但我可能错了!
class ReminderService
# @data
# ten_minute_before: data[:ten_minutes_before_reminder] bool,
# one_hour_after: data[:one_hour_after_reminder] bool,
# user: user,
# price_change_ids: data[:change_requests],
# user_hash: user_hash(user)
attr_accessor :data, :user
def initialize(user, data)
{data[:price_change_ids]}
@user = user
@data = data
end
def run
change_requests
end
def send
reminderWorker.perform_at(action_reminder_at, price_change_id, reminder_type, user, user_hash)
end
def change_requests
data[:price_change_ids]
end
def user_hash
data[:user_hash]
end
def action_reminder_at
DateTime.parse(price_change_at) - 11.minutes
end
def price_change_id
data[:price_change_ids].first.id
end
def price_change_at
data[:user_hash][:price_change_at_time]
end
end
工人服务:
class PriceReminderWorker
include Sidekiq::Worker
sidekiq_options queue: 'price_reminders', retry: true
def perform(price_change_id, reminder, user, data)
id = price_change_id
price_change = priceChangeRequest.find(id)
if reminder[:ten_minutes_before]
reminderMailer.notify(user, data).deliver_later unless price_change.cancelled_at
end
if reminder[:one_hour_after]
Sms::priceChangeSms.new(build_hash(user)).submit unless price_change.cancelled_at
end
end
def build_hash(user)
{
to: Phonelib.parse(user.mobile_number).full_e164,
company_id: user&.company&.id,
user_name: user.first_name,
admin_user_name: data[:from_admin_user],
body: Sms::Message::priceChangeMessage.new(data).build
}
end
end
解决方案
如果您真的想坚持当前的PriceChangeRequest
结构,那么我想我会这样做:
class PriceReminderWorker
include Sidekiq::Worker
sidekiq_options queue: 'price_reminders', retry: true
attr_accessor *%w( price_change_id user data ).freeze
def perform(price_change_id, reminder, user, data)
@price_change_id = price_change_id
@user = user
@data = data
%i(
ten_minutes_before
one_hour_after
).each do |time_sym|
send("send_#{time_sym}_reminder") if price_change_request.send("#{time_sym}_reminder")
end if price_change_request
end
private
def user_hash
{
to: Phonelib.parse(user.mobile_number).full_e164,
company_id: user&.company&.id,
user_name: user.first_name,
admin_user_name: data[:from_admin_user],
body: Sms::Message::priceChangeMessage.new(data).build
}
end
def send_ten_minutes_before_reminder
reminderMailer.notify(user, data).deliver_later unless price_change.cancelled_at
end
def send_one_hour_after_reminder
Sms::priceChangeSms.new(user_hash).submit unless price_change.cancelled_at
end
def price_change_request
@price_change_request ||= PriceChangeRequest.find(price_change_id)
end
end
但是,我认为在你的课堂上有一堆booleans
喜欢ten_minutes_before_reminder
的人并不是一个好主意。特别是如果您开始有许多提醒类型。您最终可能会得到稀疏填充的布尔字段,这不是那么好。而且,每次要添加新的提醒类型时,都必须运行新的迁移。等等等等等等。one_hour_after_reminder
PriceChangeRequest
如果我是你,我想我会很想上一ReminderTime
堂课,比如:
# == Schema Information
#
# Table name: reminder_times
#
# id :bigint not null, primary key
# system_name :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
class ReminderTime < ApplicationRecord
validates :system_name, presence: true
has_many :price_change_request_reminder_times
has_many :price_change_requests, through: :price_change_request_reminder_times
end
和类似的PriceChangeRequestReminderTime
东西:
# == Schema Information
#
# Table name: price_change_request_reminder_times
#
# id :bigint not null, primary key
# reminder_time_id :integer not null
# price_change_request_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
class PriceChangeRequestReminderTime < ApplicationRecord
belongs_to :reminder_time
belongs_to :price_change_request
end
然后,在您的 中PriceChangeRequest
,执行以下操作:
class PriceChangeRequest < ApplicationRecord
has_many :price_change_request_reminder_times
has_many :reminder_times, through: :price_change_request_reminder_times
def set_reminder_times(*time_syms)
time_syms.each do |time_sym|
reminder_times << ReminderTime.find_or_create_by!(system_name: time_sym)
end
end
def remove_reminder_times(*type_syms)
price_change_request_reminder_times.
where(reminder_time: ReminderTime.find_by(system_name: type_syms)).
destroy_all
end
def reminder_time_names
reminder_times.pluck(:system_name)
end
end
要设置提醒时间,您可以执行以下操作:
@price_change_request.set_reminder_times :ten_minutes_before
或者
@price_change_request.set_reminder_times :ten_minutes_before, :one_hour_after
要删除提醒时间,您可以执行以下操作:
@price_change_request.remove_reminder_times :ten_minutes_before
或者
@price_change_request.remove_reminder_times :one_hour_after, :ten_minutes_before
...这样您就可以执行以下操作:
class PriceReminderWorker
include Sidekiq::Worker
sidekiq_options queue: 'price_reminders', retry: true
attr_accessor *%w(
price_change_id
user
data
).freeze
delegate *%w(
reminder_time_names
), to: :price_change_request
def perform(price_change_id, reminder, user, data)
@price_change_id = price_change_id
@user = user
@data = data
reminder_time_names.each do |reminder_time_name|
send("send_#{reminder_time_name}_reminder")
end if price_change_request
end
private
def user_hash
{
to: Phonelib.parse(user.mobile_number).full_e164,
company_id: user&.company&.id,
user_name: user.first_name,
admin_user_name: data[:from_admin_user],
body: Sms::Message::priceChangeMessage.new(data).build
}
end
def send_ten_minutes_before_reminder
reminderMailer.notify(user, data).deliver_later unless price_change.cancelled_at
end
def send_one_hour_after_reminder
Sms::priceChangeSms.new(user_hash).submit unless price_change.cancelled_at
end
def price_change_request
@price_change_request ||= PriceChangeRequest.find(price_change_id)
end
end
推荐阅读
- vim - Vim 注释格式选项重复不起作用
- python - Heroku django 使用环境设置管理 shell (db, vars)
- tensorflow - TensorFlow 分布式估计器问题
- javascript - 取消嵌套 JavaScript Firestore 函数
- c++ - C++:如果 std::atomic_flag 是唯一的无锁原子类型,如何在 C++ 中实现无锁数据结构?
- javascript - MobX 商店没有在反应中更新
- r - 在 R 的 data.table 中,我们如何通过两列的值创建一个有序的指示变量?
- php - 传递图像数据的最佳方式
- vxworks - Vxworks 支持多道程序吗?
- html - 如何根据屏幕宽度响应设计使div移动到中间