Simplifying `rails new`

Hello! I teach quite a few people Rails through my class, Epicodus. One thing I’ve noticed is that the sheer number of files and folders rails new generates is pretty intimidating for newcomers to Rails. I’d like to make a few suggestions to how to reduce that intimidation.

  1. Don’t create the tmp and log folders. These are automatically created when rails server runs for the first time, so there’s no reason rails new needs to generate them.

  2. Combine boot.rb and environment.rb. I’ll be the first to admit I don’t understand the Rails boot process as well as I wish, and there may be implications to this I don’t understand. But in my informal testing, moving the contents of one file to another works just fine, and I personally having trouble seeing the distinction between the two.

  3. Remove internationalization by default. I could be totally off-base, but this feels like a feature that probably isn’t used by a majority of apps, and could easily be added by more experienced developers who need it (and a Rails generator could be built to easily re-install it).

  4. Move binstubs logic into the Rails gem executables. I haven’t played around with this yet and could be wrong, but I don’t see why these files need to be added to every app, when their logic could simply be included in the rails/rake/bundle/spring gem executables.

The result would be a much simpler file/folder structure for a new Rails app:

-app
-config
-db
-lib
-public

-vendor
Gemfile
Gemfile.lock
README.rdoc
Rakefile
config.ru

and a simpler config folder as well:

  • environments
  • initializers
    application.rb
    boot.rb
    database.yml
    routes.rb
    secrets.yml

which, in my experience/opinion, would make it much easier for devs to get going with Rails.

I’d love to get other folks’ thoughts on these suggestions, and if anybody is interested, work together on implementing those that others agree make sense.

Replies inline.

I agree with Michael with 2 and 4.

  1. Combine boot.rb and environment.rb. I’ll be the first to admit I don’t understand the Rails boot process as well as I wish, and there may be implications to this I don’t understand. But in my informal testing, moving the contents of one file to another works just fine, and I personally having trouble seeing the distinction between the two.

Combining boot.rb and environment.rb (and possibly application.rb) would make it easier for people to understand the booting process. boot.rb is actually misleading since rails 4 (and 3?) since this is not booting anything. application.rb could wrap all of this.

  1. Move binstubs logic into the Rails gem executables. I haven’t played around with this yet and could be wrong, but I don’t see why these files need to be added to every app, when their logic could simply be included in the rails/rake/bundle/spring gem executables.

Yes! The logic could very well live in the gem.

I have actually made a github repository last week that highlighted what I had in mind: https://github.com/pothibo/rails-flattened (bin/ folder is still present since that path is hardcoded in rails’ gem). I believe that with Rails 5, a new folder structure should be promoted that would be lighter and easier to understand for someone not used to Rails. …

I guess we could tweak this repo and try to find a right structure, if people are willing?

I agree with Michael with 2 and 4.

  1. Combine boot.rb and environment.rb. I’ll be the first to admit I don’t understand the Rails boot process as well as I wish, and there may be implications to this I don’t understand. But in my informal testing, moving the contents of one file to another works just fine, and I personally having trouble seeing the distinction between the two.

Combining boot.rb and environment.rb (and possibly application.rb) would make it easier for people to understand the booting process. boot.rb is actually misleading since rails 4 (and 3?) since this is not booting anything. application.rb could wrap all of this.

  1. Move binstubs logic into the Rails gem executables. I haven’t played around with this yet and could be wrong, but I don’t see why these files need to be added to every app, when their logic could simply be included in the rails/rake/bundle/spring gem executables.

Yes! The logic could very well live in the gem.

I have actually made a github repository last week that highlighted what I had in mind: https://github.com/pothibo/rails-flattened (bin/ folder is still present since that path is hardcoded in rails’ gem). I believe that with Rails 5, a new folder structure should be promoted that would be lighter and easier to understand for someone not used to Rails. …

I guess we could tweak this repo and try to find a right structure, if people are willing?

How would you execute the rails binary without using bundle exec within an application? Wouldn’t that defeat the purpose of binstubs? Rails isn’t installed on anything but our development machines outside of bundler.

How would you execute the rails binary without using bundle exec within an application? Wouldn’t that defeat the purpose of binstubs? Rails isn’t installed on anything but our development machines outside of bundler.

I think this is somewhat open to discussion. What is the difference between ‘bundle exec rails server’ and ‘./bin/rails server’ besides the longer command, of course?

I would personally pay the cost of longer commands to see lighter project file structure as I’m going to spend much more time in the project than I will executing commands. It’s important to note that rake tasks are going to stay as is.

I actually played with simplifying the structure some time ago, although for a completely different use case. I didn’t end up going further than posting this PoC on Github, but it does actually boot up a Rails app.

My changes:

I moved all application/environment config into a file called “{APP_NAME}.rb”. Inside this file I have a module/class definition for the application the same as any standard Rails app (looks like I accidentally made it a class rather than Application class inside APP_NAME module, oops), but I also added a Ruby DSL for specifying environment configs. IME, the files under config/environments don’t normally get a ton of options, so having them all in one place would actually be easier.

I also removed the “app” folder and put directories that were in that folder in the root. This change was specific to the particular use case I was designing this for, API-only apps that don’t have as much need for the “app” distinction.

Once I started thinking about a smaller Rails structure, the idea of the “config” folder seemed unnecessary. Anytime I need access to my app’s environment I require “application.rb”, so to me the distinction between that and “environment.rb” doesn’t serve much purpose. Given that, why can’t “boot.rb” be in the root and all the environment config be consumed into “application.rb” with a DSL for creating environments like above?

I actually played with simplifying the structure some time ago, although for a completely different use case. I didn’t end up going further than posting this PoC on Github, but it does actually boot up a Rails app.

My changes:

I moved all application/environment config into a file called “{APP_NAME}.rb”. Inside this file I have a module/class definition for the application the same as any standard Rails app (looks like I accidentally made it a class rather than Application class inside APP_NAME module, oops), but I also added a Ruby DSL for specifying environment configs. IME, the files under config/environments don’t normally get a ton of options, so having them all in one place would actually be easier.

Would this mean smashing all the files in config/initializers into one file? That would make generators that wanted to create a default initializer (for instance, the Devise InstallGenerator) much more complicated since they’d need to insert code into the singular environment.rb file rather than just drop a whole file into config/initializers.

I also haven’t seen much discussion of the “set up the paths but don’t load the whole env” reasoning for boot.rb being separate from environment.rb (mentioned down-thread by Ryan Bigg). Is this still something useful? If it isn’t, how will (for instance) Rake tasks that don’t depend on :environment be switched over?

—Matt JOnes

I actually played with simplifying the structure some time ago, although for a completely different use case. I didn’t end up going further than posting this PoC on Github, but it does actually boot up a Rails app.

My changes:

I moved all application/environment config into a file called “{APP_NAME}.rb”. Inside this file I have a module/class definition for the application the same as any standard Rails app (looks like I accidentally made it a class rather than Application class inside APP_NAME module, oops), but I also added a Ruby DSL for specifying environment configs. IME, the files under config/environments don’t normally get a ton of options, so having them all in one place would actually be easier.

Would this mean smashing all the files in config/initializers into one file? That would make generators that wanted to create a default initializer (for instance, the Devise InstallGenerator) much more complicated since they’d need to insert code into the singular environment.rb file rather than just drop a whole file into config/initializers.

I believe it would be the opposite, people, instead of using the config/initializers/*.rb, they would use mechanics that Rails provides by default - The initializer method that any railtie class have. Here’s an example of an application.rb file that would include such initializer: https://gist.github.com/pothibo/a32f686aed0f03729157

I actually played with simplifying the structure some time ago, although for a completely different use case. I didn’t end up going further than posting this PoC on Github, but it does actually boot up a Rails app.

My changes:

I moved all application/environment config into a file called “{APP_NAME}.rb”. Inside this file I have a module/class definition for the application the same as any standard Rails app (looks like I accidentally made it a class rather than Application class inside APP_NAME module, oops), but I also added a Ruby DSL for specifying environment configs. IME, the files under config/environments don’t normally get a ton of options, so having them all in one place would actually be easier.

Would this mean smashing all the files in config/initializers into one file? That would make generators that wanted to create a default initializer (for instance, the Devise InstallGenerator) much more complicated since they’d need to insert code into the singular environment.rb file rather than just drop a whole file into config/initializers.

I believe it would be the opposite, people, instead of using the config/initializers/*.rb, they would use mechanics that Rails provides by default - The initializer method that any railtie class have. Here’s an example of an application.rb file that would include such initializer:https://gist.github.com/pothibo/a32f686aed0f03729157

In your example, the generator would have to insert an additional initializer ‘whatever’ do block into the existing generator. That’s already going to make things more complicated; finding the appropriate place is not trivial, especially if the generator needs to play nice with namespaced applications, such as:

module MyTopLevel

module MyProject
class Application < Rails::Application

  initializer 'configure devise' do |app|
    app.config.devise.somethin = 'blabla'
  end
end

end

end

A simplistic strategy (“insert before the 2nd end from the end of the file”) will fall down here.

More importantly, the size of what’s added is significant. The Devise generator alone drops 260+ lines (mostly comments) to help users configure things.

The application.rb file seems like it could get quite long, and then somebody will propose to split it up into, say, a directory of smaller files… :slight_smile:

—Matt Jones

You are right. However, the initializers is not really what’s discussed here. it’s the whole directory structure. Anyway, I think config/ folder still has its place( and the initializers for all I care). I think the issue is that over the years, the project structure for Rails has grown to have a lot of different folder and the meaning of all those folders is not that obvious. Initializers were never a part of the discussion anyway until you mentionned it.

Is there any compelling argument for why the current structure is broken?

Is this just a aesthetic and/or stylistic proposal?

Most of the larger apps I work on have 10-15 files in initializers. Squashing them into on 1 file not a good option to me.

Inside the app/ folder of larger Rails apps you might have 10 different folders or more: assets, contexts, controllers, extenders, helpers, jobs, mailers, models, observers, presenters, serializers, services, uploaders, views. Having an app/ folder is a good thing IMHO, because I don’t want all these sprawled throughout my root directory.

The only thing that doesn’t make sense to me about the default Rails structure is the lib directory, which I think belongs inside of app/ since it often contains app code.

You are right. However, the initializers is not really what’s discussed here. it’s the whole directory structure. Anyway, I think config/ folder still has its place( and the initializers for all I care). I think the issue is that over the years, the project structure for Rails has grown to have a lot of different folder and the meaning of all those folders is not that obvious. Initializers were never a part of the discussion anyway until you mentionned it.

The post I originally replied to (from Joe Fiorini) mentioned the config folder potentially being unnecessary. That would tend to involve initializers. :slight_smile:

—Matt Jones