在Rails中解耦组件的惯例是什么

时间:2013-08-18 14:00:33

标签: ruby-on-rails architecture decoupling

使用rails generate model,我创建了两个模特/桌子,警察和女警。他们是具有许多属性(年龄,现场时间,案例解决等)的官员名单。如果我想做一个计算,确定谁应该获得下一次促销到Sargent的传统方式在rails中做什么?

我想创建一个新类来处理这种情况,并隐藏所有复杂的计算(比较两个列表之间的属性)远离调用者。所以也许在一个控制器中,比如Captain,在我会做的方法下

class Captain < ApplicationController
  def show
    promotion = Promotion.new
    @ideal_sargent = promotion.sargent(Policeman.find(:all),Policewoman.find(:all))
  end
end

我在哪里创建此促销课程?我是否使用rails generate controller来制作它?或者也许为它做一个宝石?或者甚至把它全部放在一个模型中(我听说瘦控制器胖模型)?

编辑: 也许this?如果是这样,如何在没有自动生成迁移文件的情况下创建模型?

2 个答案:

答案 0 :(得分:1)

您将它与模型和控制器分离的一般想法是一个好的。虽然你把它与控制器,发生器和宝石混淆了一下......

您想要做的是:

  • 介绍一个服务对象,它是普通的ruby对象
  • 将计算促销顺序的逻辑放在其中
  • 让它完全脱离控制器,与警察模型松散耦合

使用它的界面基本上就像你已经描述过的那样:

# prepare some officers to choose from
officers = [PoliceWoman.find(1)] + PoliceMan.all
# returns the first ranking officer for promotion
to_be_promoted = SargentPromotionService.new.find_top_candidate(*officers)

这个服务模式放在哪里?我想它包含特定于应用程序的逻辑,在应用程序之外并不是真的有用。因此我们将它放在app文件夹中。但在应用程序的哪个位置?

一个好的做法是设置app/domain文件夹。在那里,您可以放置​​所有应用程序特定的域模型(服务,策略,值对象等...)。您需要设置此文件夹,只需将其添加到config/application.rb

中的自动加载路径即可
config.autoload_paths += %W(#{config.root}/app/domain)

通过这种方式,您可以清楚地分离rails模型(处理持久性)和域模型 - 您应该在其中放置大多数特定于应用程序的代码。如果您的应用非常简单,那么您也可以跳过app/domain文件夹并使用app/models。如果您按照这种方法使用松散耦合的普通红宝石对象,您将获得易于测试,可维护,灵活和可重用的代码。 =)

答案 1 :(得分:0)

为此,我不会创建两个表来建模数据。我会使用一个名为polices的表,并保留一个列为性别,另一个列为不同的警察和女警,以及不同级别。然后我会将推广功能作为警察模式中的一种类方法。

class Police < ActiveRecord::Base
  def self.promote(param1, param2)
     ....
  end
end

通过这种方式,您可以在升级函数中封装业务逻辑,调用者可以在不知道任何复杂计算的情况下调用它。 Police.promote(a,b)