ruby-on-rails - Rails 模型根据用户标志调用不同的类
问题描述
学习 Rails,我刚刚遇到了一些灯可能会有所帮助的东西。
我有类,A,B,C,它们都做一个动作。
我有一个消息模型,我想在保存时根据用户输出调用其中一个类。
我现在正在努力为模型以及类编写代码的更 rubyist 方式,这取决于模型方法。
选项A:
case @user.flag:
when 'alpha'
A.new(message)
when 'beta'
B.new(message)
when 'gamma'
C.new(message)
选项B:将 A、B、C 从类移动到用户标志 名为 Functions 的模块的实例方法
Functions.send(@user.flag.to_sym,message)
由于我对 Rails 知之甚少,我正在寻找如何编写最干净和可重用的代码。提前致谢。
解决方案
与许多设计决策一样,您可以使用多种方法,每种方法都是“正确的”,主要基于偏好。这就是我的做法。
首先,我会确保@user.flags
只能采用某些值,因为它的值被用来决定其他动作。在 Ruby 中,处理这些值的普遍接受的方式也是作为符号,因为给定的符号是不可变的。
其次,由于您在Message
保存模型后对其进行操作,因此您可以利用after_save
回调并将操作保留在Message
模型本身内。这使得它与消息模型更加相关,并且总体上更具可读性。
最后,如果您的操作出现错误,您将需要某种保证,即您的保存/交易会回滚after_save
。离开这个答案,您可以通过在 `after_save_ 中引发错误来做到这一点
在app/models/user.rb
class User < ActiveRecord::Base
FLAGS = %w[alpha beta gamma].freeze
# Ensuure that `flag` field can only take on certain pre-defined values
# Also validate that flag can never be nil. You may need to change that
# as needed for your application
validates :flag, presence: true, inclusion: FLAGS
def flag
# This method isn't 100% necessary but I like to personally follow
# the pracitce of returning symbols for enumerated values
super(flag).try(:to_sym)
end
end
在app/models/message.rb
class Message < ActiveRecord::Base
after_save :post_process_message
private
# I'd recommend a better name for this method based on what you're
# specifically doing
def post_process_message
# Notice the more descriptive method name
# Also no need to pass `message` as a param since it's now located
# inside this model. You could also move it to a separate class/service
# as needed but don't over-optimize until you need to
send("handle_post_process_for_flag_#{user.flag}")
rescue StandardError => e
# Something went wrong, rollback!
# It isn't "great practice" to rescue all errors so you may want to replace
# this with whatever errrors you excpect your methods to throw. But if you
# need to, it's fine to be conservative and rescue all on a case-by-case
# basis
raise ActiveRecord::RecordInvalid.new(self)
end
def handle_post_process_for_flag_alpha
end
def handle_post_process_for_flag_beta
end
def handle_post_process_for_flag_gamma
end
end