web-dev-qa-db-ja.com

Rails:サブモジュールを作成せずにモデルをサブフォルダーに構造化するエレガントな方法

App/modelsフォルダーに多数のモデルがあります。このフォルダを少し整理したいと思います。サブフォルダー内で互いに属するモデルを移動します。問題は、慣例により、モデルクラスが対応するモジュールに名前空間化されることです。

例えば。

app/models/blog/post.rb
app/models/blog/comment.rb
app/models/user.rb

そのため:

app/models/blog/post.rb

class Post < ActiveRecord
end

ではなく

class Blog::Post < ActiveRecord
end
61
seb

Rails 3:

config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]

この構成では、Railsにすべてのapp/modelsサブフォルダーを再帰的にスキャンし、見つかったすべてのモデルをロードします。ネームスペースは不要です。

82
Ion Br.

これを行う必要があり、非常に簡単な方法があります。

モデルをサブフォルダーに移動し、Railsに、environment.rbファイル内のすべてのサブフォルダーからファイルをロードするよう指示します。

config.load_paths += Dir["#{Rails_ROOT}/app/models/*"].find_all { |f| File.stat(f).directory? }

ネームスペースは必要ありません。モデルはアプリ内で通常と呼ぶことができます

12
Tilendor

サブフォルダーも作成し、application.rbファイルに次を追加しました。

config.autoload_paths += Dir["#{config.root}/app/models/**/"]

ただし、モデルと同じ名前を使用してサブフォルダーに名前を付けた場合(たとえば、複数のファイルを含むフォルダー 'user'、そのうちの1つは 'user')、これだけでは不十分です。これにより、モデルに含まれるモデル(たとえば、「ユーザーモデル」)とは異なるフォルダー名を指定するだけで解決できることが判明するまで、コードにあらゆる種類のエラーが発生していました。 http://www.williambharding.com/blog/technology/Rails-3-autoload-modules-and-classes-in-production/ で提案を見つけました。これは実際にこの質問を指し示しています。

4
pickwick

だから私はRails 2のようなものを持っていた:

config.autoload_paths += Dir["#{config.root}/app/models/**/"]

そして、次のファイル:

  • app/models/user/base.rb:class User::Base
  • app/models/user/admin.rb:class User::Admin

Rails 3にアップグレードしたとき、次の行に沿ってエラーが発生し続けました:Expected .../app/models/user/foo.rb to define Foo。Rails 2はuser/foo.rbに入れるものは、FooだけでなくUser::Fooになります。

したがって、これを解決する方法は、autoload_pathsのモデルサブディレクトリを削除し、次のようなことをすることでした。

私はapp/models/user.rbを作成しました:

module User
  autoload :User, 'user/base'
  autoload :User, 'user/admin'
end
3
Aaron Gibralter

私のRails 3.2.3アプリでは、いくつかのモデルをサブディレクトリに移動した後、私は次のようなエラーにつまずきました

Expected /.../.../app/models/project/project_category.rb to define Project::ProjectCategory

関連呼び出し(例:Project.first.project_category)。

最後に、私が見つけた回避策は、サブディレクトリ内のモデルへのすべての関連付けに:class_nameを設定することでした...

class Project < ActiveRecord::Base

  belongs_to :project_category, :class_name => "::ProjectCategory"

end

ここでの「::」の部分は、「models/project」サブディレクトリで定義されているという事実にもかかわらず、ProjectCategoryモデルには名前空間がないというRailsを指します。

1
Tim Zaripov

たぶん、RailsEnginesを見ることができます。それはまさにあなたが必要とするものではありませんが、いくつかのアイデアを与えることができます。

それ以外は、スクリプトが正常に動作するようであれば(モデルの各サブフォルダーにあるすべてのファイルを読み取って必要な場合もあります)、それに対する問題は発生しません。

1
Yaraher

tilendorのこのバージョンのソリューションは、Rails 3

config.load_pathsとRails_ROOTは、Rails 3で非推奨になりました。また、environment.rbではなく、config/application.rbのconfigブロックに配置する必要があります

config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/*"].find_all { |f| File.stat(f).directory? }
1
chris_b

これはRails 5。

以下をapplication.rbに追加します

config.autoload_paths += Dir[ Rails.root.join('app/models/**/') ]

ただし、フォルダにモデルと同じ名前を付けることはできません。

1
Fellow Stranger

上記のすべての答えは私にはうまくいきませんでした。どういうわけか「models」フォルダーにサブフォルダーがロードされ、「::を含むことが予期されていました」という結果になりました。

私のサブディレクトリのほとんどはSTIクラスであったため、それらをapp/models_sti // *に移動しました。その後、私がする必要があるのは、application.rb

#config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/**/"]
# Loaded dynamically (cache_classes == false ?)
config.autoload_paths << Rails.root.join('app', 'models').to_s
config.autoload_paths += Dir["#{Rails.root.to_s}/app/models_sti/*"].find_all { |f| File.stat(f).directory? }

# Eager_load_paths - used only when cache_classes == true [Rails spec says so]
config.eager_load_paths.delete_if do |path|
  # If I didn't delete it from eager_load_paths I got errors even in develop
  path == Rails.root.join('app', 'models_sti').to_s
end
config.eager_load_paths += config.autoload_paths
0
Kangur

より良い解決策が見つかるまで、app/modelsフォルダーにinit.rbを作成しました。

app/models/init.rb

%w[blog].each do |folder|
  path = [File.dirname(__FILE__), folder, "*.rb"].join('/')
  Dir[path].each {|file| require file }  
end

これまでの目的を果たす。

0
seb