学习Rails时,我只是遇到一些可能会有帮助的东西。
我有A,B,C类,它们都可以执行操作。
我有一个Message模型,当我要保存时,我想根据用户输出来调用这些类之一。
我现在正在努力寻找一种更红宝石的方式来编写模型代码以及类,具体取决于模型方法。
选项 A :
case @user.flag:
when 'alpha'
A.new(message)
when 'beta'
B.new(message)
when 'gamma'
C.new(message)
选项 B : 将A,B,C从类移动到用户标记(称为函数)的模块的实例方法
Functions.send(@user.flag.to_sym,message)
由于我对Rails的了解很少,因此我正在寻找如何编写最干净和可重用的代码。预先感谢。
答案 0 :(得分:1)
与许多设计决策一样,您可以采用多种方法,每种方法都是“正确的”,主要是基于偏好。这就是我的做法。
首先,我将确保@user.flags
仅可以采用某些值,因为它的值被用于决定其他动作。在Ruby中,由于给定符号是不可变的,因此处理这些值的普遍接受的方式也是符号。
第二,由于您在保存Message
模型后要进行某些操作,因此可以使用after_save
callback并将操作保留在Message
模型本身中。这使其与消息模型的联系更加紧密,并且通常更具可读性。
最后,如果after_save
操作出错,您将需要某种保证,即保存/事务会回滚。从this answer开始,您可以通过在`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
答案 1 :(得分:0)
这是一个有趣的问题,正如@ user2490003所说,没有写/错误的方法可以做到这一点。
您的方法将根据A,B和C类的实现方式及其表示形式以及方法在每个类中的作用而改变。
让我们举个例子,一个名为talk
的方法和两个类Man
,Women
。
因此,您可以将其实现为
class Man
def talk
# talk like an adult
end
end
class Women
def talk
# talk like an adult
end
end
但是,正如您所看到的,talk
和Man
的{{1}}方法是相同的,并且您还可以看到它们通常共享相同的功能和属性。因此,创建一个名为Women
的基类,并在其中移动Human
方法
talk
现在让我们举一个婴儿的例子,说婴儿class Human
def talk
# talk like an adult
end
end
class Man < Human
end
class Woman < Human
end
与男人和女人不同,尽管婴儿仍然继承自talk
。在这种情况下,您可以
Human
这里发生的是,婴儿将从人类继承,但是当您致电
class Baby < Human
def talk
# baby talk
end
end
它在Baby类(不是Human类)中执行
Baby.new.talk # => baby talk
方法
让我们得到一个talk
类,并假设它也有一个Parrot
方法,并且它与talk
相同。
现在存在的问题是我们无法从Human talk
继承Parrot
类,但是我们仍然希望在Human
方法中包含代码。在这种情况下,您可以使用模块,因此可以
talk
正如我所解释(或至少尝试过..)那样,您的实现将取决于类A,B,C和Message类之间的关系。
在这种情况下,我个人要做的是拿笔和纸,尝试映射这些对象,而无需考虑如何以红宝石或任何语言实现。一旦了解了它们如何相互连接,就很容易找到实现它的语法