2

2 つのモデル: AnOwnerと a Dog:

owner.rb

class Owner < ActiveRecord::Base
  has_one :dog
end

dog.rb

class Dog < ActiveRecord::Base
    belongs_to :owner
end

そして、ここにスキーマがあります:

schema.rb

ActiveRecord::Schema.define(version: 123) do

  create_table "dogs", force: true do |t|
    t.string   "name"
    t.integer  "energy"
    t.integer  "owner_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "dogs", ["owner_id"], name: "index_dogs_on_owner_id"

  create_table "owners", force: true do |t|
    t.string   "name"
    t.string   "energy"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

かなりシンプルなセットアップ。

彼を散歩ownerに連れて行きたい。dog散歩が終わると、飼い主の気力が5減り、犬の気力が20減る。

明らかに、このwalk_the_dogアクション/メソッドは、ownerオブジェクトとオブジェクトの 2 つのオブジェクトに影響を与えdogます (もちろん、この犬のオブジェクトはたまたまこの所有者に関連付けられています)。

このコードをどこに置くべきかわかりません。内で単純にアクションを作成できることはわかっていますがowners_controller.rb、それは悪い考えのように思えます。次のようになります。

owners_controller.rb

class OwnersController < ApplicationController
    def walk_the_dog
        @owner = Owner.find(params[:id])
        @owner.energy -= 5
        @owner.dog.energy -= 20   # this line in particular seems like bad OO design
        @owner.save
        @owner.dog.save
    end
    ...
 end

私が理解しているように、オブジェクトは自分自身の状態のみを変更する必要があり、他のオブジェクトの状態を変更するべきではありません。ownerオーナー コントローラ内でオブジェクトだけでなく、関連付けられたオブジェクトの状態も変更しているため、これは悪い考えのように見えdogます。

サービスについて読みました。walk_the_dog私が理解しているように、サービスはオブジェクト間の相互作用と複数のオブジェクトの状態変更を可能にするため、サービスの優れたケースのようです。私はそれを行う/実装する方法がわかりません。

と呼ばれるサービスオブジェクトが必要walk_the_dogですか? 一連のサービスメソッドを含むサービスディレクトリ内のファイルである必要があります-そのうちの1つが呼び出されwalk_the_dogowners_controller.rbコントローラーでこのメソッドを使用するだけですか? 次のステップが何かわかりません。

: 「これが OO 設計を壊すかどうかなんて誰が気にするんだろう。ただそれを実行して、うまくいくならうまくいく」と言っている人を見ることができます。残念ながら、これはオプションではありません。私が今取り組んでいるアプリケーションは、その考え方に従いました。アプリケーションが非常に大きくなり、現在は維持が非常に困難になっています。アプリの大幅なリニューアルでこの状況を打破したい。

4

2 に答える 2

1

このコードをリファクタリングする場合に行ういくつかのことを次に示します。

コードに数値を記述するのは悪いことです。数値を定数として定義したENERGY_PER_WALK_FOR_DOG = 20か、より良い方法はDogモデルのテーブルにフィールドを定義することです。このようにして、それらの値を管理および割り当てる方がはるかに優れています。

add_column :dogs, energy_per_walk, :integer, default: 20
add_column :owners, energy_per_walk, :integer, default: 5

ApplicationControllerクラスにメソッドを作成します:

def walk(resources = [])
  resources.each do |resource|
    resource.lose_walk_energy # you can refine it more!
  end
end

フォルダーapp/models/concernsに、次のモジュールを記述します。

module Walkable
  extend ActiveSupport::Concern


  # subtract energy_per_walk form the energy saved in db
  def lose_walk_energy
    self.energy -= self.energy_per_walk
    save
  end

end

そして今、あなたのメソッドは次のメソッドに縮小されます:

def walk_the_dog
  @owner = Owner.find(params[:id])
  walk([@owner, @owner.dog])
end
于 2015-06-11T16:22:37.697 に答える