I am facing an issue where my Rails application is set to cache classes when run in the staging or production environment. While load_paths only contains 'app/models', it appears that the initialization steps recursively caches everything in 'app/models'.
# Eager load application classes
def load_application_classes
if configuration.cache_classes
configuration.eager_load_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
end
end
end
end
The problem in this is that we have a sub directory within 'app/models' that contains files with require statements that reference a concurrent JRuby environment. Since Rails knows nothing of this environment our application breaks on load.
As it stands, here are the proposed solutions...unfortunately only #1 is ideal.
1) The simplest solution would be to exclude the culprit sub directory, but have not found anything how to accomplish this.
2) Monkey patch the load_application_classes method to skip the specific sub directory.
3) Move the sub directory out from under 'app/models'. Feels a bit hackish and would require quite a few code changes.
Thoughts?
As a temporary measure you could go with a version of option 2 and override the definition of load_application_classes, replacing it with an empty implementation. That would force you to explicitly require the classes you need but it would give you complete control over what gets loaded and would be a completely transparent solution.
It sounds like your application is sufficiently sophisticated that it's growing beyond the Rails framework. I know that this doesn't directly answer your question so appologies in advance but you may want to consider looking at an alternative Ruby framework like Merb. Rails is great but sooner or later you bump into edge of the framework - sounds like that's where you are now.
We made the switch to Merb last year and haven't regreated it.
Chris
Related
This issue relates to a need to set a Rails config variable as the application boots, and the value of that variable needs to come from data in the database (which are then modified). So, I have an initializer with something like this:
require "#{Rails.root}/lib/modules/facet_altering.rb"
include FacetAltering
Rails.application.config.reject_subjects = FacetAltering.reject
The reject method is potentially slow and calls the Subject model (which includes some concerns).
If I try to require subject.rb, application_rb and the relevant concerns from app/models then I progress a bit further, but eventually get stuck on uninitialized constant Subject::MySpecialConcern.
There might be some better way to set the reject_subjects value; I'd prefer not to run FacetAltering.reject each time the value of reject_subjects is used, though this might be an easy 'fix' if no other solution arises (at the cost of slowing things down). Or, is there another way to access these classes as the application boots?
Edit: Following on from the comment below, this is in config/application.rb:
%W[#{Rails.root}/lib/modules #{Rails.root}/test/mailers/previews].each do |path|
config.eager_load_paths << path
end
This post offered a useful clue:
Rails Model no longer available in initializer after upgrade to Rails 7.0
So, putting my code in config/application.rb as follows did the trick:
config.after_initialize do
Rails.application.config.reject_subjects = FacetAltering.reject
end
Now to find the answer to RuntimeError: Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. and I might be able to complete this Rails 6 -> 7 upgrade!
To load a Ruby file only if it is necessary, I did this in a project:
XController ...
...
if(!user.last_ip_country_id || user.last_login > Date.today - 1.week)
require 'ip_to_country.rb'
Thinking about how Ruby on Rails runs, does it make sense to do this? Should it be at the top? Or, is there any advantage for requiring a file only when needed (like lazy load)?
If that part of the code is executed once at the start, then it makes sense to do that. And in fact, there are authentic codes that do that. Typical examples are when you want to require different gems or local files depending on your environment.
Also when the file to be loaded has its own name space that does not interact with the other part of your code, then, you can do lazy loading at an arbitrary point in your code.
Otherwise, i.e, if that part of the code is executed repeatedly during use and the file to be loaded may interact with the rest of the code (such as by monkey patching common classes), then it is not a good idea to do that because it would be more difficult to consider the interaction of your code with the gem if it were loaded in the middle of the code at a specific timing.
When I notice things like: 0.15s in my specs for a simple method like:
class String
def to_slug
(self.dup).gsub(/["']/, '').gsub(/#/, 'at').gsub(/&/, 'and').parameterize
end
end
I start to ask myself what is going on, so after benching the method without parameterize I decided this was a problem inside of parameterize and not necessarily with the method itself but, well, with the way it's loaded, it seems to me like it's lazily loaded when Monkey Patches like that should be eager loaded, it is causing latency where it should not exist IMO. So my questions are, does Rails really lazily load the file that contains parameterize and is there way to convince Rails to eager load patches to String and other stdlib's.
Calling config.threadsafe! in your config/environments/test.rb should force all code to be loaded at boot time. Note that this will set cache_classes to true, so don't use it in development environment or you will lose code reloading.
Another way would be to change config.eager_load_paths to include the directory you want to load.
Resources:
Aaron Patterson explains config.threadsafe! in his article Removing config.threadsafe!.
The Rails guide on configuration has a lot of information on each option.
When you create a namespaced model with rails scaffolding, you get two files. For example, this scaffold:
rails generate model Staff::Location name:string address:string
Generates these files:
/app/models/staff.rb
module Staff
def self.table_name_prefix
"staff_"
end
...
/app/models/staff/location.rb
class Staff::Location < ActiveRecord::Base
...
I am running into problems when in development mode where rails unloads the Staff module and never reloads it. This causes several annoying bugs such as Location not able to access it's table due to the missing table_name_prefix. The problem seems to crop up when I don't access the models directly, such as through a polymorphic relationship.
I can't seem to get the module loaded on a consistent basis. Is this the best practice way to do namespaced models? If it is, what am I missing?
Although I wasn't able to reproduce the problem in Rails 3.2.2, I've run into something like this before. The generic way to hack around this problem in development mode is through an ActionDispatch callback. Add this to config/environments/development.rb:
MyApp::Application.configure do
ActionDispatch::Callbacks.before do
load Rails.root.join('app', 'models', 'staff.rb')
end
end
Anything you do in that block will be executed before each request, so make sure you're only doing it in development mode.† Otherwise, you're going to suffer a performance hit in production.
I logged a message inside the staff.rb file and within the Staff module itself, and both messages appeared in the log for each request.
† I tried using the to_prepare callback, since that seems to be the documented way to execute code before each request only when cache_classes is false. But that only seemed to execute after restarting the application. There's at least one other open Stack Overflow question regarding this, although he's using a slightly different syntax than I used. If you can get to_prepare to work, I'd suggest that instead of before.
About a year later, I have finally found the answer to this question. This answer is specifically for rails 3.1. I am not sure if it is a problem in rails 3.2.
The problem occurs when setting up a model. If scaffolding is used, no helper file is generated. This would normally be in /app/helpers/staff/location_helper.rb. There are two ways to setup this file:
module Staff::LocationHelper
...
end
module Staff
module LocationHelper
...
end
end
In rails 3.1, specifically for helpers, you must use the first solution. You do not have to use it for other modules that use a namespace in other parts of the rails project. In fact, some structures in ruby require the second solution.
If you use the second solution when declaring a helper, in certain cases the Staff module in the helper file will override the module in /app/models/staff.rb. It will silently replace it with the empty Staff module in the file. This does not happen 100% of the time because helpers are not always loaded.
I have a more conceptual question in Rails... or Ruby for that matter:
Is it best to call a require right before the method that needs it, group my requires at the beginning of the class or somewhere in an initializer when Rails boots?
Does it matter from a performance point of view? From a readability point of view? Does it make a difference if I'm using Rails 3?
Thanks!
If you're concerned about performance then you should require things in the context of where they are needed so that if that portion of your code is not exercised, the library is not loaded. Any subsequent calls to require have no effect as that file has already been loaded. This ends up looking like something along the lines of:
if (user.using_openid?)
require 'openid'
# ... Do OpenID stuff
end
While this is more efficient in terms of resources, it can make it very difficult to determine the dependencies of your application. Declaring these up-front makes it clear to other people maintaining the software. Keep in mind that "other people" always includes your future self when you've forgotten about some details of your application.
You're technically allowed to require anything at any time, late or early, but declaring your requirements up front is better from a design perspective. If you find that there is an element that is used only intermittently and takes an unusual amount of time or memory to load, then you should probably document that up front in your requirements file. For example:
require 'library1'
require 'library2'
require 'library3'
require 'library4'
require 'library5'
# Other libraries loaded as required:
# * slowimagelibrary
# * slowencryptionlibrary
# * openid
Arguably this is less of an issue with bundler because you can have your gems declared up front more formally and the actual require call can come later.
If you consider vanilla Ruby, 'require' is mostly used in the first lines, because you then are sure you have access to what you need, and it is easier to find and read what dependency you need.
There are a few cases when you want to load a gem only in a method, because this is not really needed for your script to work (e.g.: a optional visualization).
With Rails, I believe it depends on what you want to do.
If you use Bundler, you can assume your gem has been 'required' (you can of course override what is required with the :require option).
If it is some stuff you want to autoload when the server start (like validators or form builders), then you should look how to do with the config (autoload_paths and eager_load_paths).
require can also be used to load only a part of a gem, like an extension to it. Then it is of course required where the configuration is.
You might be concerned if you work in a multi-threaded environment, as they are some problems with that. You must then ensure everything is loaded before having your threads running. (Something like the class constant is loaded, but the methods not yet, there was a good article but I can not find it anymore).
You might also want to try {Module,Kernel}.autoload, Rails extensively use it to load only what is necessary when accessed (but it looks rather ugly).
You can also hack it yourself with const_missing (so this can do plain lazy-loading, if you accept a structure).
This is a simple example (will not be appropriate for nested classes).
def Object.const_missing c
if (file = Dir["#{c.downcase}.rb"]).size == 1
require_relative(file)
end
if const_defined? c
const_get c
else
super # Object < Module
end
end
About performance, a call to require is relatively expensive, so if you know you are going to use it, do it only once if possible. However, to manage complex dependencies within your project, you might need to require relative files. Then require_relative is the way to go in 1.9.
Lastly, for a project, I would recommend to require all in the main file in lib/, with some Dir["**/*.rb"] expression. You would then rarely need to require_relative, because it is only needed if you reference in the body of the class another constant (all the contents of the methods are not resolved, so there is no problem with that).
Another solution would be to define these constants in your main file, it would also give you an idea of the structure.