0

我正在开发一个应用程序。基本的东西,用户注册(与相关组织)。

最初我从一个简单的控制器开始 -

# Need to check if organization exists already; deny user creation if it does 
if @organization.save
  @user.save
  redirect_to user_dashboard_path...

我很快发现自己陷入了回调汤:

验证组织后,我们保存用户。创建组织后,我创建了另外两个模型,EmailTemplate 和 PassTemplate(一个组织 has_one :email_template,has_one :pass_template)

  after_create :init_company, :init_email_template, :init_pass_template, :init_form

这些回调中的每一个通常都会调用模型上的方法,例如:

def init_email_template
  self.email_template.create_with_defaults
end

最初我认为这很聪明——在幕后做了这么多,但我一直在阅读 Steve McConnell 的 Code Complete,觉得这一点都不简单。如果我不知道已经发生了什么,那么没有任何迹象表明任何时候创建组织都会创建 3 个关联对象(其中一些对象反过来会初始化子对象)。

这似乎是一种糟糕的编程习惯,因为它混淆了正在发生的事情。

我考虑将所有这些初始化移动到控制器,因为一个组织只创建一次:

class OrganizationsController < AC
  ...
  def create
    if @organization.save
       @organization.create_user
       @organization.create_email_template
       @organization.create_pass_template
  end

这似乎是更简洁的代码,并且更容易遵循。

问题 1 *是否有更好的解决方案或最佳实践来处理在创建中心对象时创建我不知道的关联对象?*

旁注 - 我将不得不重写一堆假设关联是通过回调自动创建的测试 - 如果它更好,更容易理解代码,我可以接受。

问题 2 **after_save 回调的类似情况如何?**

我有一个客户模型,它在创建后检查它是否有关联的 user_account,如果没有,则创建它。一旦我们创建了 user_account,它还会为该 user_account 创建一个 Tag 模型

class Customer < AR
  after_create :find_or_create_user_account

  def find_or_create_user_account
     if !self.user_account_exists?
        #create the user
     end
     Tag.create(:user_id => self.user_account.id)         
  end
end

有点简化,但我相信这不是特别好的编程。一方面,我将逻辑放在第三个模型中创建两个不同的模型。似乎马虎又一次分离逻辑的原则。其次,方法名称并没有完全描述它在做什么。也许 find_or_create_user_account_and_tag 会是一个更好的名称,但它也违背了让方法只做一件事的原则——保持简单。

在阅读了观察者和服务之后,我的世界陷入了一个循环。

几个月前,我把所有东西都放在了控制器中。不可能很好地测试(这很好,因为我没有测试)。现在我的控制器很瘦,但我的模型很肥胖,而且我认为不健康(不清楚,不明显,几个月后另一个程序员/我自己更难阅读和破译)。

总的来说,我只是想知道是否有一些关于逻辑分离、避免回调汤以及不同类型代码的好指南、信息或最佳实践

4

1 回答 1

1

为什么不是以下?

after_create :init_associated_objects

def init_associated_objects
  init_company
  init_email_template
  init_pass_template
  init_form
end

我对“一个方法应该做一件事”的解释并不严格,而且我通常有一个调用其他方法的方法(很像上面的那个)。归根结底,这是一种分而治之的策略。

有时,当拥有 AR 模型没有意义但一组功能是类的责任时,我会创建实用程序 PORO(普通的旧 ruby​​ 对象)。例如,报告不是 AR 支持的模型,但是当需要调用多个模型的报告只实例化一次时,报告期的开始和结束是实例变量,这样会更容易。

我遵循的一条经验法则:如果我在整个 MVC 堆栈(例如 Rails 控制台)之外实例化模型,我期望发生的事情应该留在模型中。

我没有声称最佳实践,但到目前为止这些对我有用。我相信其他人对此会有更好的想法。

于 2013-03-06T03:43:07.083 回答