【问题标题】:Rails: too many methods in modelRails:模型中的方法太多
【发布时间】:2017-01-11 01:08:01
【问题描述】:

TL;DR:我不知道如何组织我的逻辑域类。

我有“应用程序”模型,该模型位于应用程序的“核心”中,是我“进入”并操作其他模型的方式,例如:

@application = Application.find(params[:application_id])
@application.payment.update_attribute 'active', true

   unless @application.report.status 

   @application.set_income(params[:income][:new_income])

所以模型 Payment、Income 和 Report 基本上是空的,因为我初始化了 Application 模型,然后我从那里“级联”做一些事情来改变“从属”模型。但现在 Application 模型有四十多个方法和 600 行代码。

我做得对吗?例如,当我想添加我喜欢做的新付款时:

payment = Payment.create params  

在 Application 模型中,因为 ActiveRecord“知道”如何自动处理外键。我可以使用以下方法在付款模型中创建付款:

application = Application.find(application_id)
params[:application_id] = application.id
self.create params

但是这样一来,我需要手动设置 Application.id,这看起来更冗长且不优雅。

那么——如果我想减少我的应用程序模型——我应该在 APP/lib 目录中创建模块还是应该将方法移动到其他模型?

【问题讨论】:

  • 棘手的问题,因为我们不知道这 40 种方法。有些可以转移到其他模型,有些可以转移到助手。您还可以在其他模型中构建方法来优雅地创建新支付等。

标签: ruby-on-rails ruby oop


【解决方案1】:

我应该在 APP/lib 目录中创建模块吗

基本上,是的,这就是你应该做的。虽然我可能会让它们成为类而不是模块。听起来您所追求的模式称为“服务对象”(或有时称为“用例”)。这样做是从您要执行的特定操作中获取逻辑,并将其放入它自己的自包含类中。然后该类与它需要的任何模型协作。因此,您的模型保持很小,并且您的“服务类”遵循单一职责原则。然后,您的控制器通常会调用一个“服务类”来完成他们需要做的事情 - 因此您的控制器也保持极小。

如果您在 Google 上搜索“rails 服务对象”或类似内容,您会发现很多很棒的东西,但这里有一些资源可以帮助您入门。

服务对象 rails casts:https://www.youtube.com/watch?v=uIp6N89PH-c

https://webuild.envato.com/blog/a-case-for-use-cases/

https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/(那里有一节关于服务对象)

请记住,一旦您开始使用服务对象,您不必总是通过您的Application 模型来获得相关的对象。服务对象可能会采用application_id,然后执行例如。 @payment = Payment.find_by(application_id: application_id),因此您根本不需要获取应用程序实例,并且可以直接操作 @payment 变量。

Rails 使获取相关模型变得“简单”和“漂亮”这一事实并不一定意味着您应该这样做。

【讨论】:

    【解决方案2】:

    我不会担心 Rails 中的长控制器和规范文件。

    这些文件往往会变得很长,保持类和方法简短的通常建议不一定适用于控制器及其规范。

    例如,在我们的生产系统中,user_controller.rb 的长度为 8500 行,而对应的 user_controller_spec.rb 的长度为 7000 行。

    这是我们前 10 个控制器的长度

    1285 app/controllers/*********_controller.rb
    1430 app/controllers/***********_controller.rb
    1444 app/controllers/****_controller.rb
    1950 app/controllers/****_controller.rb
    1994 app/controllers/********_controller.rb
    2530 app/controllers/***********_controller.rb
    2697 app/controllers/*********_controller.rb
    2998 app/controllers/*****_controller.rb
    3134 app/controllers/application_controller.rb
    8737 app/controllers/users_controller.rb
    

    【讨论】:

      【解决方案3】:

      TL;DR:如果您的应用程序有四个模型都与数据库中的表相关联(即利用 ActiveRecord 并从 ActiveModel::Base 继承),则该框架非常倾向于使用模型类。

      服务类模式的抽象在某些情况下可能很有用,但请让自己休息一下。 Rails 的优点之一是它应该通过为您制定组织决策来消除许多开发障碍。利用您的模型类。

      让我们看看这是否会引发一场史诗般的开发者争吵。

      另外,可以在模型中创建接口以创建相关模型:

      class Application < ActiveModel::Base
        has_one :payment
      
        def create_payment(attrs)
          payment.create(attrs)
        end
      end
      

      好吧,我的意思是框架将允许这样做。但请记住,您已经继承自 ActiveModel::Base,它定义了许多实例方法,包括 create

      我会推荐,尤其是。如果这是一个小项目,而您刚刚开始涉足,请使用知名的 rails 控制器来读取对象并将对象写入数据库:

      class ApplicationPaymentsController < ActionController::Base
        def create
          application = Application.find(params[:id])
          application.create_payment(payment_params)
        end
      
        private
      
        def payment_params
          params.require(:payment).permit(:x, :y) - whatever your attr names are.
        end
      end
      

      Rails 关联为您提供了在创建关系记录时抽象外键时所寻求的流畅性:

      http://guides.rubyonrails.org/association_basics.html(好的起点)

      http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_one(更明确的文档)

      如果这是您的目标,这将帮助您精简模型。只是为了澄清,这是开发人员非常固执己见的事情之一,无论如何,但事实是存在代码异味(应该解决),然后有些人任意宣扬文件长度最大值。这一切中最重要的是可读的代码。

      一个很好的重构工作代码的试金石将它搁置几周,然后再回来,如果它令人困惑,那么花一些时间使它变得更好(希望以已经编写的测试覆盖率为指导)。否则,请尽情享受你所做的事情,尤其是当你独自工作时。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-03
        • 1970-01-01
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多