Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having both rails and rake commands is confusing: Just use rails as the command router. #18878

Closed
dhh opened this issue Feb 10, 2015 · 34 comments

Comments

@dhh
Copy link
Member

dhh commented Feb 10, 2015

Some commands live under rails others under rake and to the user it's not clear that there's a rhythm nor rime. Let's route all the rake commands through the rails command. It's still helpful and useful to use rake tasks such that we can allow others to declare task dependencies and such, but there's no reason it has to be exposed through rake on the CLI.

So after this, it should be rails test and rails db:setup.

@dhh dhh added the railties label Feb 10, 2015
@dhh dhh added this to the 5.0.0 milestone Feb 10, 2015
@arthurnn arthurnn self-assigned this Feb 10, 2015
This was referenced Feb 10, 2015
@acutemedical
Copy link

I have to say thanks for this. Routing all rake tasks through the rails command really keeps things clean. Can't wait until this is implemented. Any chance of backporting to 3.2 4.1 4.2? I'm sure tons of people would love this.

@rafaelfranca
Copy link
Member

@teknull we don't backport any new feature, sorry.

@acutemedical
Copy link

@rafaelfranca I figured that was the case, but one can dream. Some of us still have 3.2 apps floating out there. :)

@rafaelfranca
Copy link
Member

Yeah. I'm in the same boat 😢

@dziulius
Copy link

How about also fixing environment setting for rails command?
rails server -e some_env
rails console some_env

@waiting-for-dev
Copy link

Shouldn't be better to only use rake and let to the rails command the only responsibility to create a new project? rake is the 'default' in all ruby world.

@dhh
Copy link
Member Author

dhh commented Feb 13, 2015

rake has a variety of issues around parameter parsing that we want to get around to increase the comfort of the CLI. And besides the app generator, we have a bunch of other generators. So filing everything under rails and delegating to rake where we can makes the most sense to me.

On Feb 13, 2015, at 02:08, Marc Busqué notifications@github.com wrote:

Shouldn't be better to only use rake and let to the rails command the only responsibility to create a new project? rake is the 'default' in all ruby world.


Reply to this email directly or view it on GitHub.

@joevandyk
Copy link
Contributor

Is it possible to fix the rake parameter handling?

@dhh
Copy link
Member Author

dhh commented Feb 16, 2015

Exactly because rake is so embedded in everything, I think it makes change hard. But if someone wants to explore that, that's fine. I think we're still going to route it through the Rails command, since having servers like "rails server" and "rails console" as rake commands doesn't make much sense to me. But it would mean we'd have to do less hacking to get there.

@haswalt
Copy link

haswalt commented Feb 18, 2015

I second this. Rake parameter parsing is broken and nobody seems interested in looking at a fix over there. As a hole it makes more sense to have the rails command route everything and avoids confusion.

I don't think there needs to be a match to the other systems out there, we all know of rake but when we're dealing with rails applications we're in the rails world. A lot of the time I find myself writing rake tasks that access parts of rails anyway so make more sense to tie them in to me.

@waiting-for-dev
Copy link

I don't like the idea about creating too many parallel worlds... if rails is going to use anyway rake (which is a very reasonable decision, because it is the most mature ruby based task manager) I think it would be better to reduce complexity and only use it.

Reading the comments, I think that the overall impression is that rake would be better but rake has an unsolved problem. So, in my view, this should be reduced to estimating the cost of solving that problem vs the complexity of having two worlds. I know my point is very lazy because I'm not going to implement it and I also talk with a lot of ignorance, but this is how I see things from the outside.

@dhh
Copy link
Member Author

dhh commented Feb 18, 2015

Marc, we’re going to have parallel worlds regardless. “rails server” and “rails console”, to take just two, will never be rake tasks. Rake is an implementation detail for interacting with the Rails framework.

On Feb 18, 2015, at 11:14, Marc Busqué notifications@github.com wrote:

I don't like the idea about creating too many parallel worlds... if rails is going to use anyway rake (which is a very reasonable decision, because it is the most mature ruby based task manager) I think it would be better to reduce complexity and only use it.

Reading the comments, I think that the overall impression is that rake would be better but rake has an unsolved problem. So, in my view, this should be reduced to estimating the cost of solving that problem vs the complexity of having two worlds. I know my point is very lazy because I'm not going to implement it and I also talk with a lot of ignorance, but this is how I see things from the outside.


Reply to this email directly or view it on GitHub.

@joevandyk
Copy link
Contributor

What's wrong with "rake console"?

@rafaelfranca
Copy link
Member

rake console -e development will not work.

@joevandyk
Copy link
Contributor

I would love that to be able to work. :)

@waiting-for-dev
Copy link

I see... I guess there is not beautiful way to implement "magic" rake commands like rake console:development (now it comes to my mind seedbank gem does something like that). Or it could be RAILS_ENV=development rake console just like in rake db:migrate, but I agree last one is a little cumbersome (but also for db:migrate).

@dhh
Copy link
Member Author

dhh commented Feb 18, 2015

Ship has sailed. This is the path we’re moving forward with now. Let’s move on to the next bikeshed. There are so many left to discuss :)

On Feb 18, 2015, at 12:50, Marc Busqué notifications@github.com wrote:

I see... I guess there is not beautiful way to implement "magic" rake commands like rake console:development (now it comes to my mind seedbank gem does something like that). Or it could be RAILS_ENV=development rake console just like in rake db:migrate, but I agree last one is a little cumbersome (but also for db:migrate).


Reply to this email directly or view it on GitHub.

@rafaelfranca
Copy link
Member

👍 🚲

@Spaceghost
Copy link

But now I can't write rake tasks that use those tasks as dependencies. 😦

@dhh
Copy link
Member Author

dhh commented Feb 25, 2015

Sure you can. We are keeping the tasks that makes sense as rake tasks so you can depend on them. We just allow you to call those through the rails command.

On Feb 24, 2015, at 16:34, Johnneylee Jack Rollins notifications@github.com wrote:

But now I can't write rake tasks that use those tasks as dependencies.


Reply to this email directly or view it on GitHub.

@Spaceghost
Copy link

@dhh Oh, that's a lot less heart attack inducing. Thank you.

@rails rails locked and limited conversation to collaborators Feb 25, 2015
@schneems
Copy link
Member

It would be pretty easy to change the behavior here to call the task instead of giving a message #7891

@kaspth kaspth added pinned and removed stale labels Jul 3, 2015
@dhh
Copy link
Member Author

dhh commented Jul 8, 2015

This task is open to anyone who wants to explore it again.

@rails rails unlocked this conversation Jul 8, 2015
@repinel
Copy link
Member

repinel commented Jul 8, 2015

I'd be glad to take a look.

@repinel
Copy link
Member

repinel commented Jul 9, 2015

@schneems Yes, it would be easy to change the rake checking to run the command if it's valid. While there wouldn't be a need to whitelist the tasks, it would be slower than running the tasks directly with rake since --dry-run can take some time.

Then I tried something like this and the runtime was a little better, but it seems wrong to load the environment to validate the tasks.

require APP_PATH
Rails.application.load_tasks
system("bin/rake #{command}") if Rake::Task.task_defined?(command)

Suggestions?

schneems added a commit to schneems/rails that referenced this issue Jul 24, 2015
Currently when you accidentally run `$ bin/rails db:migrate` you got an error message:

```
Error: Command 'db:migrate' not recognized
Did you mean: `$ rake db:migrate` ?
```

After this change you'll still get an error message, but it will also run the command:

```
$ be rails routes
Error: Command 'routes' not a valid rails command
Running: `$ bin/rake routes` instead

                  Prefix Verb     URI Pattern                                           Controller#Action
                teaspoon          /jstest                                               Teaspoon::Engine
           users_sign_in GET      /users/sign_in(.:format)                              redirect(301, /users/auth/github)
           users_sign_up GET      /users/sign_up(.:format)                              redirect(301, /users/auth/github)
        new_user_session GET      /users/sign_in(.:format)                              devise/sessions#new
            user_session POST     /users/sign_in(.:format)                              devise/sessions#create
# ...
```

I highly recommend that we keep the warning message. Without it running `$ rails --help` won't show all available commands and `rails db:migrate` would be a touch too magical for my tastes. If we want to switch over documentation so that some commands such as `rails test` work out of the box, we should whitelist them. The alternative would be we add the `$ rake -T` output to `$ rails --help` and that would get pretty messy. 



Thanks to @repinel for the tip on speeding up the rake check
@schneems
Copy link
Member

Here's a potential implementation #21012

@dhh
Copy link
Member Author

dhh commented Jul 29, 2015

I think that's a clever quick hack, but the goal here is that the user
should never need to go to rake for Rails commands. So don't like telling
them that calling "rails command" is wrong, and that we're doing them a
special favor by running rake for them.

Also, calling out to system sounds like it might be way slow. But maybe
it's not if we have spring loaded?

On Wed, Jul 29, 2015 at 6:10 PM, Richard Schneeman <notifications@github.com

wrote:

Here's a potential implementation #21012
#21012


Reply to this email directly or view it on GitHub
#18878 (comment).

@schneems
Copy link
Member

It's not all that slow on my machine, though I didn't do any kind of benchmarks. It's definitely faster than waiting on the whole command to fail and then manually re-typing in your rake command. I've got spring perma disabled in my .bashrc for rails dev work, though that would help most rails devs. Since we've already got the rake tasks in memory we could manually use Rake::Task#invoke if you're worried about speed, though we would have to re-parse the command to remove any flags like -T or --trace

The biggest concern about moving in the direction of all bin/rails all the time for me is documentation and behavior. For documenting these commands we could either dump them all to the rails --help output:

$ rails --help
Usage: rails COMMAND [ARGS]

The most common rails commands are:
 generate    Generate new code (short-cut alias: "g")
 console     Start the Rails console (short-cut alias: "c")
 server      Start the Rails server (short-cut alias: "s")
 test        Run tests (short-cut alias: "t")
 dbconsole   Start a console for the database specified in config/database.yml
             (short-cut alias: "db")
 new         Create a new Rails application. "rails new my_app" creates a
             new application called MyApp in "./my_app"

In addition to those, there are:
 destroy                            Undo code generated with "generate" (short-cut alias: "d")
 plugin new                         Generates skeleton for developing a Rails plugin
 runner                               Run a piece of code in the application environment (short-cut alias: "r")
 about                              List versions of all Rails frameworks and the environment
 assets:clean[keep]                 Remove old compiled assets
 assets:clobber                     Remove compiled assets
 assets:environment                 Load asset compile environment
 assets:precompile                  Compile all the assets named in config.assets.precompile
 cache_digests:dependencies         Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
 cache_digests:nested_dependencies  Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
 db:create                          Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use  db:create:all to create all databases in the config)
 db:drop                            Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use  db:drop:all to drop all databases in the config)
 db:fixtures:load                   Loads fixtures into the current environment's database
 db:migrate                         Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
 db:migrate:status                  Display status of migrations
 db:rollback                        Rolls the schema back to the previous version (specify steps w/ STEP=n)
 db:schema:cache:clear              Clears a db/schema_cache.dump file
 db:schema:cache:dump               Creates a db/schema_cache.dump file
 db:schema:dump                     Creates a db/schema.rb file that is portable against any DB supported by AR
 db:schema:load                     Loads a schema.rb file into the database
 db:seed                            Loads the seed data from db/seeds.rb
 db:setup                           Creates the database, loads the schema, and initializes with the seed data (use db:reset to also  drop the database first)
 db:structure:dump                  Dumps the database structure to db/structure.sql
 db:structure:load                  Recreates the databases from the structure.sql file
 db:version                         Retrieves the current schema version number
 dotenv                             Load environment settings from .env
 initializers                       Print out all defined initializers in the order they are invoked by Rails
 log:clear                          Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)
 middleware                         Prints out your Rack middleware stack
 notes                              Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)
 notes:custom                       Enumerate a custom annotation, specify with ANNOTATION=CUSTOM
 rails:template                     Applies the template supplied by LOCATION=(/path/to/template) or URL
 rails:update                       Update configs and some other initially generated files (or use just update:configs or update:bin )
 resque:failures:sort               Sort the 'failed' queue for the redis_multi_queue failure backend
 resque:work                        Start a Resque worker
 resque:workers                     Start multiple Resque workers
 restart                            Restart app by touching tmp/restart.txt
 routes                             Print out all defined routes in match order, with names
 schedule:mark_closed               Marks issues as closed
 schedule:poke_inactive             Sends an email to invite users to engage once a week
 schedule:populate_issues           Populates github issues
 schedule:triage_emails             Sends triage emails
 secret                             Generate a cryptographically secure secret key (this is typically used to generate a secret for  cookie sessions)
 stats                              Report code statistics (KLOCs, etc) from the application or engine
 teaspoon                           Run the javascript specs
 test                               Runs all tests in test folder
 test:db                            Run tests quickly, but also reset db
 test:javascript                    Run the javascript test
 time:zones:all                     Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET  parameter, e.g., OFFSET=-6
 tmp:clear                          Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear)
 tmp:create                         Creates tmp directories for cache, sockets, and pids

But that gets a bit messy, or we could do something like heroku where we have named categories so we could list off rails db in the help section and running rails db --help would output all name-spaced rails db commands. What are your thoughts on docs?

The second issue I see is that we're hiding rake functionality. When a rake task fails, I often will re-run it with --trace or --verbose to get more information about why it failed. We're making using rake debug flags a silent and non-discoverable feature. This isn't a show stopper but it's worth mentioning.

@dhh
Copy link
Member Author

dhh commented Jul 29, 2015

I like "rails db --help" for section lists, but I don't think we need to be
piping the docs via rake. We can just move over all the documentation and
expand upon it. The whole rake setup should be deprecated (regardless of
whether that's what we use on the backend to execute some rails commands).

I like --verbose and --trace both. Should work both for commands we
delegate to rake and others.

On Wed, Jul 29, 2015 at 8:37 PM, Richard Schneeman <notifications@github.com

wrote:

It's not all that slow on my machine, though I didn't do any kind of
benchmarks. It's definitely faster than waiting on the whole command to
fail and then manually re-typing in your rake command. I've got spring
perma disabled in my .bashrc for rails dev work, though that would help
most rails devs. Since we've already got the rake tasks in memory we could
manually use Rake::Task#invoke if you're worried about speed, though we
would have to re-parse the command to remove any flags like -T or --trace

The biggest concern about moving in the direction of all bin/rails all the
time for me is documentation and behavior. For documenting these commands
we could either dump them all to the rails --help output:

$ rails --help
Usage: rails COMMAND [ARGS]

The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
test Run tests (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a
new application called MyApp in "./my_app"

In addition to those, there are:
destroy Undo code generated with "generate" (short-cut alias: "d")
plugin new Generates skeleton for developing a Rails plugin
runner Run a piece of code in the application environment (short-cut alias: "r")
about List versions of all Rails frameworks and the environment
assets:clean[keep] Remove old compiled assets
assets:clobber Remove compiled assets
assets:environment Load asset compile environment
assets:precompile Compile all the assets named in config.assets.precompile
cache_digests:dependencies Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
cache_digests:nested_dependencies Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
db:create Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config)
db:drop Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config)
db:fixtures:load Loads fixtures into the current environment's database
db:migrate Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
db:migrate:status Display status of migrations
db:rollback Rolls the schema back to the previous version (specify steps w/ STEP=n)
db:schema:cache:clear Clears a db/schema_cache.dump file
db:schema:cache:dump Creates a db/schema_cache.dump file
db:schema:dump Creates a db/schema.rb file that is portable against any DB supported by AR
db:schema:load Loads a schema.rb file into the database
db:seed Loads the seed data from db/seeds.rb
db:setup Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)
db:structure:dump Dumps the database structure to db/structure.sql
db:structure:load Recreates the databases from the structure.sql file
db:version Retrieves the current schema version number
dotenv Load environment settings from .env
initializers Print out all defined initializers in the order they are invoked by Rails
log:clear Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)
middleware Prints out your Rack middleware stack
notes Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)
notes:custom Enumerate a custom annotation, specify with ANNOTATION=CUSTOM
rails:template Applies the template supplied by LOCATION=(/path/to/template) or URL
rails:update Update configs and some other initially generated files (or use just update:configs or update:bin )
resque:failures:sort Sort the 'failed' queue for the redis_multi_queue failure backend
resque:work Start a Resque worker
resque:workers Start multiple Resque workers
restart Restart app by touching tmp/restart.txt
routes Print out all defined routes in match order, with names
schedule:mark_closed Marks issues as closed
schedule:poke_inactive Sends an email to invite users to engage once a week
schedule:populate_issues Populates github issues
schedule:triage_emails Sends triage emails
secret Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)
stats Report code statistics (KLOCs, etc) from the application or engine
teaspoon Run the javascript specs
test Runs all tests in test folder
test:db Run tests quickly, but also reset db
test:javascript Run the javascript test
time:zones:all Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET parameter, e.g., OFFSET=-6
tmp:clear Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear)
tmp:create Creates tmp directories for cache, sockets, and pids

But that gets a bit messy, or we could do something like heroku where we
have named categories so we could list off rails db in the help section
and running rails db --help would output all name-spaced rails db
commands. What are your thoughts on docs?

The second issue I see is that we're hiding rake functionality. When a
rake task fails, I often will re-run it with --trace or --verbose to get
more information about why it failed. We're making using rake debug flags a
silent and non-discoverable feature. This isn't a show stopper but it's
worth mentioning.


Reply to this email directly or view it on GitHub
#18878 (comment).

@ccallebs
Copy link
Contributor

@schneems Are you still working on this? If not, I can give it a shot.

@schneems
Copy link
Member

Feel free to take a shot.

@ccallebs
Copy link
Contributor

I've implemented a potential solution. I chose the whitelisting approach, as it seemed undesirable to have Rails be a mediator for all rake tasks (even custom ones that may not rely on Rails at all). If it's a requirement to have the rails command be a catch-all for rake tasks, that should be easy enough to implement. As @repinel pointed out, the latter approach would be slower than explicitly defining the commands, so I think whitelisting them still has a strong benefit even if the "catch-all" route is taken.

@kaspth
Copy link
Contributor

kaspth commented Dec 13, 2015

Fixed @ #22288 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests