This came from a newbie that is learning Rails. He had the console running while adding a model and a mailer in another terminal session, then he went to the and tried to create a new record of that model but instead got a NameError.
He expend and hour trying to figure out what was going on until he sent me a message and told him to use the reload! command from the console and that solved his problem.
I don’t see the point of having the console to be reloaded on every code change automatically but it will be very helpful if it can display a message telling the user that code was change and in order for that code to be available in the console a reload! is need it.
It’s a natural idea to have, but this is done to avoid surprises. Let me explain.
Reloading can’t happen in the middle of a session. Imagine a script run got class definitions changed in the middle of the execution, that would have impredictable consequences. In a console session is the same, you ran
> joe = User.new
then you edit user.rb, an automatic reload happens and do
> alice = User.new
Now, joe and alice belong to two different class objects. Everything previous becomes stale in ways that are going to confuse.
Reloading is only active if you run the web server. Other commands like runner, migrations, generators, console, etc., don’t have a reloader in place to run with a consistent set of classes an modules.
The reload! command is provided so that users can consciously opt-in if they want to, at their own risk.
I remember this one taking me a little while to learn too, way back when.
Can we drill down a little more on the logic you expect? One way I could see of implementing the thing you’re describing:
Have listen or similar detect a code change.
Have it output a message to the Rails console like “Code change detected; remember that you need to reload.”
Now, for an experienced Rails dev like me, I can see that message getting SUPER ANNOYING, so I would want something like this to be opt-out. But I can see how it might help provide “training wheels”
of a sort.
I think having an in-line notice that the code was changed, and to reload if you want those updates in the session, would be great. Doubt it’s going to be annoying even to experienced devs. If you have an active console session, and you’re changing classes in the background, you probably want to see those changes reflected!
I understand why we don’t want to do it automatically, but that’s mostly a matter of surprise and timing. If I’m in a console session, and I’m changing classes in the background, I pretty much always want to use reload shortly thereafter.
I get why this should not happen automatically on every change. I’ve been doing Rails for a while, and always remember that I need to reload con code change.
Some sort of warning in the console prompt should not be annoying and helpful for newcomers.
A warning here from my experience: Even seasoned Ruby programmers do not fully understand how classes, modules, and constants work, and how decoupled they are of each other.
The consequences of having stale objects in scope would be poorly understood and a source of confusion.
I am also afraid of inviting people to reload with a message, many won’t understand the risk and will be puzzled when stale objects interact with new ones in an apparently erratic way.
If anything of this is ever implemented, I’d suggest to either print a big warning (smell?), and/or see if you traverse ObjectSpace looking for orphan class and module objects or instances of orphan classes, to warn loudly about their existence.
I am all for sharp knives. In this case, the existence of reload! is the sharp knife. Going beyond that is very risky in my opinion.
I agree with the reasons for not automated reloading. Then again, I can still remember that it was confusing when I started with Rails, and moreover, it was hard to find relevant information. For a long time I thought I was doing it wrong, closing and restarting the console.
Maybe the solution is not changing the behaviour, but document it.
Add the reload behaviour to the description in the Guide with rails console
Add the difference between reload! and restart too.
And maybe add a shortcut rails c restart. Because nowadays, I have a terminal screen open to do rails restart all the time. Would be nice if I could restart the console from there too.
Actually, the stale object point could be entirely sidestepped if instead of reload, we reboot. Simply start a brand new console session within the current one. Blow away all existing object references.
I like this idea. I wonder whether it’s feasible to do something similar in a dev-server environment, to finally kill the User does not have the same class as User loader fart that (as Avdi observed elsewhere) has been a tiny but persistent “missing stair” in Rails for at least eleven years. (Can’t speak to Rails WTFs from before I started using Rails. )
I have some ill-formed gut-level usability concerns about completely blowing away a console session, having to do with people building up complicated test data structures and then being sad when they’re unexpectedly blown away. Messaging might help here.
Tell the user inline in the console: “The class MagicMonkey was changed. To use the new changes either reload!, and manually discard old instances, or reboot!, to have all local and instance variables cleared.”
I know what you’re saying here, but if you stay in the stale session (without reloading) and wonder what happened to your changes that you just typed, that’s pretty awful, too. I actually like DHHs suggestion, that we just restart the session entirely. Maybe a warning line that you need to start hitting the up-arrow to get your objects back…
I like reboot! because after a reload! I’m often reminded to re-initialize objects only after getting class mismatch errors. These errors push me to agree even more with Xavier’s points about surprises.
Consider reboot! also reloading a .pryrc, which contains my favorite test subject
#.pryrc
# Pry Console Aliases
# Inspired by https://pawelurbanek.com/rails-console-aliases
def me
@me ||= User.find_by(email: `git config user.email`.strip)
end
Not sure, but an auto-reload might be handy sometimes when I don’t want to throw together a quick unit test to beat on something. I like both a command-line option for one-off use and a configuration option for established use.
When enabled, please communicate the hidden magic like we do for spring…
$ rails c --auto-reboot
Running via Spring preloader in process 70313 <== I like this reminder
Automatically reboot when code changes are detected. <== Tell me about hidden magic
Loading development environment (Rails 6.0.3)
[1] pry(main)>
I value the current behavior in reload! as it allows me to easily test what happens if I want to change part of my working system - load existing models, initialize whatever new objects I’m planning to add, then call something like reload!; TestObject.new(existing_stuff).rerun to get very quick feedback on my changes.