81

Would it be possible to have something like this?

app/models/
app/models/users/user.rb
app/models/users/education.rb

The goal is to organize the /app/models folder better, but without having to namespace the models.

An unanswered question for Rails 3 is here: Rails 3.2.9 and models in subfolders.

Specifying table_name with namespaces seems to work (see Rails 4 model subfolder), but I want to do this without a namespace.

pdobb
  • 17,688
  • 5
  • 59
  • 74
Rubytastic
  • 15,001
  • 18
  • 87
  • 175
  • I understood that you dont want namespace, but i think the best way to do that is using ActiveSupport Concerns. – Nando Nov 28 '13 at 18:43
  • 2
    @NandoSousa. No. ActiveSupport Concerns are for shared behaviour. The way you use models. – berkes Jun 16 '15 at 15:36

1 Answers1

117

By default, Rails doesn't add subfolders of the models directory to the autoload path. Which is why it can only find namespaced models -- the namespace illuminates the subdirectory to look in.

To add all subfolders of app/models to the autoload path, add the following to config/application.rb:

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

Or, if you have a more complex app/models directory, the above method of globing together all subfolders of app/models may not work properly. In which case, you can get around this by being a little more explicit and only adding the subfolders that you specify:

config.autoload_paths += Rails.root.join("app", "models", "<my_subfolder_name1>")
config.autoload_paths += Rails.root.join("app", "models", "<my_subfolder_name2>")

UPDATE for Rails 4.1+

As of Rails 4.1, the app generator doesn't include config.autoload_paths by default. So, note that the above really does belong in config/application.rb.

UPDATE

Fixed autoload path examples in the above code to use {*/} instead of {**}. Be sure to read muichkine's comment for details on this.

pdobb
  • 17,688
  • 5
  • 59
  • 74
  • 6
    Tried it but it fails with a Unable to autoload constant User::Credits, expected /srv/books/app/models/user/credits.rb to define it. So it still wan't the files to be named spaced. Placed them above the lib entry as suggested. – Rubytastic Sep 21 '13 at 18:36
  • 1
    This error is actually good news. It means it found the file. But, you're using an odd pluralization here. If your file name is `app/models/user/credits.rb` then make sure the class name in the file is also plural: `class Credits`. But, I would recommend to use the Rails standard and make it `class Credit` and the file name be `app/models/user/credit.rb` (models should be singular). Either way, this should be the problem. Let me know! – pdobb Sep 21 '13 at 18:44
  • beside the singular i have the class named "class Credits < ActiveRecord::Base" thought I restarted the server it works fine now, strange. Must have forgot to restart it. Thanks for this answer saves a lot of headache and much less clutter in the models folder :) – Rubytastic Sep 21 '13 at 18:51
  • Thanks for the rails 4 update. It's helpful for those of us who jumped in when the shift was made to rails 4, and aren't always sure if this is a genuine 'answer out of date' or a 'This isn't the file you're looking for.' – RonLugge Dec 01 '14 at 20:01
  • 1
    In Rails 4.1 config I use `config.autoload_paths += %W( #{Rails.root}/app/models/namespace #{Rails.root}/app/models/other_namespace )` – Epigene Apr 02 '15 at 08:08
  • 14
    `config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]` works but slows the application down, specially in development mode where the app is reloaded often. The reason is that you must not add all the files to the autoload_paths but only the root folders where then file names and modules can be inferred from. In simple termes, if you have only one level of subfolders into models and no namespace models, you should only do `config.autoload_paths += Dir[Rails.root.join('app', 'models', '*/')]` which adds only the first level of sub directories. Same for `lib` or other paths. – muichkine Oct 14 '15 at 14:16
  • @muichkine Very interesting, thanks. Do you have a source for that knowledge? I'm definitely going to try it out. – pdobb Oct 14 '15 at 14:21
  • 3
    @pdobb it's experience :) if you look at how auto loading works you will see that it loops at all `auto_loading_paths` to which it adds the inference for the model. For instance if you have `NameSpace::Model` it will try to find in all the autoloading_paths a `path/namespace/model`. This can obviously match only when `path` is a directory. As a rule of thumb, you should only have directories in the `autoload_paths` for maximum efficiency. Hope it helps. – muichkine Oct 14 '15 at 15:52