Summary: in development, requests are routed to workouts_controller.rb but in production to workouts_controllerPrev.rb
In a Rails 5.2.3 app, I have the file workouts_controller.rb in the controllers/ folder with first line:
WorkoutsController < ApplicationController
I took a copy of workouts_controller.rb (to serve as a quick reference backup) which I renamed to workouts_controllerPrev.rb and retained in the controllers/ folder.
I then introduced some new functionality to workouts_controller.rb. I tested the new functionality locally (it worked as expected in development) and then I deployed to Heroku (v 7.42.0) (for production).
The new functionality, however didn’t work in production. After some debugging, I identified that in production, the WorkoutsController class in workouts_controllerPrev.rb was handling calls to the Workouts controller (rather than the Workouts controller defined in workouts_controller.rb (as anticipated and as happening in development).
I made a more dramatic name change to workouts_controllerPrev.rb, changing it to Xwurkouts_controllerPrev.rb, and changed the class name in this file to XWurkoutsController redeployed and it all worked fine.
What is happening here? Why would Rails function differently in this respect between the 2 environments? Is this a bug or an unsurprising consequence of a bad practice of having unused files loitering around? If a bug, where should I report it?
I am using SQLite in development, and PostGreSQL in production, but I don’t see this can be a database issue? The production webserver is Puma.
Thanks for any guidance
Daniel
The issue is that both files have the same class name in them, so the actions (methods) in whichever one is loaded last will override the actions defined in the one loaded first.
If you want to keep both files around and not have surprising results, change the class name in the old file to something else like PrevWorkoutsController.
Or, save it in a branch in Git so it doesn't clutter your current code.
To answer about why you got different results in different environments, it is because of the difference between autoloading vs. eager loading. Rails uses autoloading in development, but it eager loads everything up front in production, then turns autoloading off.
In other words, in development, Rails will reload the class from its matching file any time that file is saved. In production, it simply loads all files up front, so whichever one it loads last will win.
You can read more here.
Related
I want the following file structure:
app/components/foo/foo.rb
app/components/foo/_foo.html.haml
app/components/bar/bar.rb
app/components/bar/_bar.html.haml
Where I then can access the different classes like this:
Components::Foo
Components::Bar
Right now, for autoloading to work properly, it has to be structured/coded/accessed like this (hypothetically according to Rails convention):
Components::Foo::Foo
Components::Bar::Bar
That makes no sense. I want the previously mentioned file structure because I want my classes to be self-contained together with any resources/etc. belonging to them. I know that if the ruby file goes right inside app/components all will be well, but that means I have one folder and one file to keep track of, instead of just one folder. Not very nice.
Now, what's bothering me is that, just like the scenario presented here: Rails unable to autoload constant only on first attempt, the autoloading clearly works, but always only on the 2nd attempt. Since it is so systematic, it feels like it should be possible to configure things correct for it to work on the 1st attempt at all times.
This is the only addition I've made to the application.rb:
config.eager_load_paths += Dir[Rails.root.join('app', 'components', '**/')]
I'm aware that a server restart is necessary in case new directories are added/existing directory structure is modified, but that's fine since that doesn't happen very often. Modifying the code obviously happens very often, and while I can keep refreshing the page multiple times until it has re-loaded all the constants, it is very frustrating (and tbh I haven't even tested it in production, but wouldn't be surprised if it does the same thing there on the first load).
I'm also aware that you might be able to work around this by using manual requires etc., and while I haven't had much luck with that anyway, it is still a much inferior solution since it would require a server restart if code is modified (assuming the requiring is done in a central place, such as in an initializer or in application.rb).
I am upgrading a Rails app from 4.2.x to 5.0.x. After I updated all my Rails-related gems in Gemfile, I ran the rails task for updating all my files to conform to the newest version, as per the upgrade guide:
rails app:update
There were many conflicts in this command, so I pressed a to accept all conflicts and then review them manually before committing them. My main concern is what happened to the config/routes.rb file. Basically, the entire contents of the file, save for the Rails.application.routes.draw block and a single comment about the DSL added to the end of the file, were kept. All routes that have been added to the app over the years were cleared out, not to be found in any other file.
This issue doesn't block me, I'll simply checkout the file to bring it back to its former state. However, what especially concerns me is that an essential file was cleared out in what appears to be a normal situation for upgrading a Rails version. I'd like to see if anyone else has run into this issue, whether this is expected, what's going on. Comments from Rails maintainers are welcome. Thank you.
The app:update task is just a slightly modified version of the task that creates a new Rails application. It writes out files under config/ and bin/ based on the templates from the new Rails version. If you selected a to accept all conflicts, then that simply means that Rails is going to overwrite any differing files with its own copy without asking you. This is normal and expected. If you don't want that behavior, then don't press a.
config/routes.rb is almost certainly the one file under config/ that will differ almost completely from the empty boilerplate file.
Realistically, Rails can't be expected to parse your custom changes and merge them with a new template.
For what it's worth, I like to start out doing exactly what you did, with a clean working directory just let the app:update task overwrite anything it wants to, and then go through all the changes with a side-by-side, SCM-aware diff tool like vim-fugitive to stage or discard the differences.
Well, just don't accept all conflicts, take a look in each one of it. Making version upgrades of 1 level of magnitude may change a lot of things and the process takes a while.
First take a look on the changes in the framework and do the process carefully. You may be breaking a lot more stuff that you are not noticing:
http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-4-2-to-rails-5-0
I read a post about the rails load_paths, here is the link.
But, I am still confused about the difference between the autoload_paths and eager_load_paths:
I have tested them in a newly created Rails 4 project. It seems that they run the same way, that auto-reload in the development mode but in the production mode.
Author of the linked article here. Here's an attempt to clear up the confusion, going off of #fkreusch's answer.
In Ruby you have to require every .rb file in order to have its code run. However, notice how in Rails you never specifically require any of your models, controllers, or other files in the app/ dir. Why is that? That's because in Rails app/* is in autoload_paths. This means that when you run your rails app in development (for example via rails console) — none of the models and controllers are actually required by ruby yet. Rails uses special magical feature of ruby to actually wait until the code mentions a constant, say Book, and only then it would run require 'book' which it finds in one of the autoload_paths. This gives you faster console and server startup in development, because nothing gets required when you start it, only when code actually needs it.
Now, this behavior is good for local development, but what about production? Imagine that in production your server does the same type of magical constant loading (autoloading). It's not the end of the world really, you start your server in production, and people start browsing your pages slightly slower, because some of the files will need to be autoloaded. Yes, it's slower for those few initial requests, while the server "warms up", but it's not that bad. Except, that's not the end of the story.
If you are running on ruby 1.9.x (if I recall correctly), then auto-requiring files like that is not thread safe. So if you are using a server like puma, you will run into problems. Even if you aren't using a multi-threaded server, you are still probably better off having your whole application get required "proactively", on startup. This means that in production, you want every model, every controller, etc all fully required as you start your app, and you don't mind the longer startup time. This is called eager loading. All ruby files get eagerly loaded, get it? But how can you do that, if your rails app doesn't have a single require statement? That's where eager_load_paths come in. Whatever you put in them, all the files in all the directories underneath those paths will be required at startup in production. Hope this clears it up.
It's important to note that eager_load_paths are not active in development environment, so whatever you put in them will not be eagerly required immediately in development, only in production.
It's also important to note that just putting something into autoload_paths will not make it eager-loaded in production. Unfortunately. You have to explicitly put it into eager_load_paths as well.
Another interesting quirk is that in every rails app, all directories under app/ are automatically in both autoload_paths and eager_load_paths, meaning that adding a directory there requires no further actions.
Basically, autoload_paths are paths Rails will use to try loading your classes automatically. E.g. when you call Book, if that class isn't loaded yet, it will go through the autoload_paths and look for it in those paths.
In production, it might be better to load those upfront to avoid autoload concurrent issues. For that, it provides the eager_load_paths. Paths in that list will be required upfront when your application starts.
I've searched fairly extensively for any advice and have yet to find it so, here goes:
My Rails project fails to automatically reload models in development. Reloading them currently requires a full server restart.
Previous instances of this issue have been related to non-activerecord files placed in the models directory, though this is not the case for me.
config.cache_classes is properly set to false in my development config file. Views and controllers reload without issue.
All of my rails components are version 3.2.11. I have tried disabling all of my development-specific gems to no avail. This is obviously not a productivity stopper, but it is quite an annoyance. Any help appreciated and I am happy to provide more information if it would help, though I am not using any exotic gems.
Thanks!
Some possibilities:
You are not really running on developement environment
You are changing a model within a namespace and didn't told rails to autoload the path
You are changing a file that is included in your class, not your class directly (or any of the many variants for this)
You are caching classes
Considerations:
Things might change according to the webserver you are using
How do you know it's not reloading?
I ask my question because I was having the exact same issue when I was trying to insert a debugger into what I thought was a piece of code that was being executed. I assumed the model wasn't being reloaded since it was not hitting the debugger but it was actually a call back that was redirecting me around the code with the debugger line in it.
So, it might be something other than your models not being reloaded.
I am a former PHP developer learning Rails and Sinatra. In PHP, every page request loaded all of the required files. If I changed some code and refreshed the page, I could be sure that the code was fresh.
In Rails 3, Controller code is fresh on every request. However, if I modify any code in the /lib folder, I need to restart the server so the changes take effect.
Why does this happen? Is it something to do with the way Ruby is designed? Is Rails doing some optimizations to avoid reloading code on every request?
Thanks!
Edit: I am mostly interested in what is going on under the hood. Do frameworks like Rails and Sinatra do some special caching for classes? If so, what does they do? Is the default behavior in Ruby that all code gets reloaded on every request? Why do we need tools like Shotgun for Sinatra (http://sinatra-book.gittr.com/#automatic_code_reloading)?
While you are in development mode you should tell Rails not to cache your classes so they reload each time. This means that each request the classes are basically redefined in the rails interpreter. The setting in your Rails.root/config/environments/development.rb:
config.cache_classes = false
The classes the are in your lib/ dir are usually loaded through an initializer and not subject to this setting.
When you move to production you will want all of your classes to be cached so requests are faster and rails will do optimizations to things like scopes on your models.
You could put something in another initializer (maybe called Rails.root/config/initializers/development_reload.rb) that reloads the lib dir with every request in development (or just the ones you are working on):
# file development_reload.rb
if Rails.env.development?
ActionDispatch::Callbacks.after do
load 'filename_in_lib'
# or
Dir.entries("#{Rails.root}/lib").each do |entry|
load entry if entry =~ /.rb$/
end
end
end
I am calling "load" so it actually reloads the file, whereas "require" would just check if it has been loaded and determine it already has so it will not reload it. (I just threw this together and don't use it, but Ruby is extremely flexible and will allow you to do quite a bit.) Use something like this wisely and only in a dev environment.
Why code needs to be reloaded in Rails 3?
Ruby is an interpreted language (JRuby has some support for precompilation, but it's still interpreted). Interpreting the the definition of classes once on initialization is similar to compiling php and deploying in executable format (somewhat). The interpreter is not bothered with redefining classes all the time.
Forcing the explicit reload is an optimization for this type of interpreted language. (if you AOT compile in php you would need to reload the compiled "bytecode" after changes as well; default php uses on-the-fly compilation which is what you are taking advantage of)
How about a more high level approach:
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader.prepare!
This was taken from Rails/ActiveRecord v3.2.13 - active_record/railtie.rb
The load approach didn't work for me. Just performing load caused a weird issue where it would trigger certain validators twice for me.
In order to fix that, I tried Object.send(:remove_const, User) before reloading User, but then I lost my observers on that class, so I started chasing my tail.
The above approach reloads all the classes, so maybe there is still yet a better approach to properly remove an individual class from cache and reload it...