20

初期の Rails プロジェクトに取り組んでおり、Rubocopを使用してコード スタイルを分析しています。Ruby のネストされたクラスが Rails のコンテキストでどのように機能するのか、正確に疑問を抱くようになりました。たとえば、私のエンジンには次のモデルがあります。

# app/models/app_core/tenant.rb
module AppCore
  class Tenant < ActiveRecord::Base
  end
end

そしてコントローラー:

# app/controllers/app_core/tenant/members_controller.rb
module AppCore
  class Tenant::MembersController < ApplicationController
  end
end

モデルの場合、モジュールはパスと同じで、クラス名はファイル名と同じです。コントローラーの場合、パスの 2 番目の部分である「tenant」はクラス名の一部です。

Rubocopは「コンパクトなスタイルではなく、ネストされたクラス定義を使用する」というTenant::MembersController行で言っているので、正しく理解すれば...

module AppCore  
  class Tenant
    class MembersController < ApplicationController
    end
  end
end

...これは違いはありません。

さて、私の質問は、AppCore::Tenant をモデルとして持っているということですが、AppCore::Tenant が再び開かれているように見え、MembersController クラスがネストされたクラスとして追加されています。これは、私の Tenant クラスには常にそのネストされたクラスがあるということですか? モデルとコントローラーのルートに別の名前を付ける必要がありますか? これはまったく問題なく、心配する必要はありませんか? これが何を意味するのか正確にはわかりません。

4

3 に答える 3

24

微妙な違いの 1 つは、スコープが異なることであり、これによりエラーが発生する可能性があります。最初のケースではAppCore、定数は で検索されますが、2 番目のケースでは、定数は で検索されAppCore::Tenantます。定数名を完全に修飾しても、違いはありません。

Foo = :problem

module A
  Foo = 42

  # looks up A::Foo because of lexical scope
  module B
    def self.foo
      Foo
    end
  end
end

# looks up ::Foo because of lexical scope
module A::C
  def self.foo
    Foo
  end
end

# Looks up A::Foo, fully qualified ... ok technically ::A::Foo is fully qualified, but meh.
module A::D
  def self.foo
    A::Foo
  end
end

A::B.foo # => 42
A::C.foo # => :problem
A::D.foo # => 42

AppCore::Tenant内部から定義された定数を参照している場合MembersController、違いが生じる可能性があります。微妙ですが、おそらく重要であり、知っておくとよいでしょう。Utilサブモジュールを持つモジュールを持っていたとき、私は実際にこれにぶつかりましたString。メソッドを に移動したところ、そのメソッド内で が参照されたUtilため、壊れました。その後、いくつかの命名規則を変更しました。StringUtil::String

モジュールTenantは常にMembersControllerネストされたクラスとして保持されます。参照できるコードベースの他の場所AppCore::Tenant::MembersController。より良い分離が必要な場合は、モデル クラスに別の名前を付けるか、AppCore::Modelまたは類似のモジュール内に配置する必要があります。Rails を使用している場合は、いくつかの規則を破る必要がありますが、そのために必要な構成はそれほど悪くありません。

于 2014-06-24T17:47:32.817 に答える
0

技術的な詳細について質問されていることは承知しており、Sami が回答しています。しかし、私は自分自身を助けることができず、尋ねなければなりません:

そもそも志望理由って何かあるんですか...

  1. ...階層のような「パス」を導入しますか?
  2. ...コントローラーをモデルクラス内に配置しますか?

1) の必要性を感じた場合、おそらく、実際のパスをエコーする単純な「コンテナー」モジュールが必要になるでしょう。つまり、app/model/tenant.rb=>Model::Tenantapp/controller/members_controller.rb=>Controller::MembersControllerです。

しかし、率直に言って、その背後にある理由はよくわかりません。コントローラーは、慣習によってすでに簡単に見つけられXyzControllerます。モデルは (ほとんどの場合だと思いますが) ドメインに似た性質を持っているため、かなり簡単に認識されます。ruby はパス名をクラス名に一致させることを必要とせず、またそれを提案することさえないので (例えば、Java とは異なり)、明確な 1 レベルの命名規則の方が私にとってはより便利です。

サブモジュール/サブクラスの階層、名前空間のように機能して衝突を回避する gem にとって非常に便利です。むしろ必須です。

2) (モデル内のコントローラー) は根本的に間違っています。コントローラーはモデルとは非常に異なり、モデル内には存在しません。

于 2016-01-14T20:24:41.890 に答える