Why Rails6+ started adding activesupport requires in config/environments/* by default? - ruby-on-rails

I'm a bit late with Rails version upgrade. What surprised me was a bunch of active_support requires in config/environment/* files generated by Rails.
What are they for? Does it have something to do with Zeitwerk that was introduced in Rails6?
I don't remember them being present in older versions of Rails.
ag ^require config/environments
config/environments/development.rb
1:require "active_support/core_ext/integer/time"
config/environments/test.rb
1:require "active_support/core_ext/integer/time"
config/environments/production.rb
1:require "active_support/core_ext/integer/time"
Steps to reproduce:
rails new myapp
cat Gemfile | grep "^gem 'rails'"
gem 'rails', '~> 6.1.3', '>= 6.1.3.2'
I tried to find this update in rails/rails CHANGELOG and some git blaiming but that didn't help.

A little bit further down each environment file, the code that the require statement loads is used (or is referenced in comments, in the case of the production file). From the default development.rb:
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp/caching-dev.txt').exist?
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}" # <- NOTE THIS LINE
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
That require statement adds support for expressions like 2.days.to_i - core_ext/integer/time loads some functions, but also requires core_ext/numeric/time.
So the require statement is being a good Ruby citizen, and making sure that the particular part of Rails that its code relies upon is guaranteed to be loaded in order to be able to parse that line correctly.
I don't know why it wasn't needed before (it could be a Zeitwerk-related issue, as you suggest, that's a part of Rails 6+ I'm not too familiar with yet).
But at the end of the day, if the whole Rails stack is loaded before this file is evaluated, the require won't have any additional effect – and if it's not, this file will load what it needs and then the rest of Rails will load as needed.

Related

Rails 5: rails s production with config.eager_load=true fails while gem 'gem_name', require: false

I've been struggling to deploy an application in production with config.eager_load = true.
I know this configuration loads most of Rails and application code in memory, and it's a nice feature to have in production(like) environments, the problem is that i have a custom rails engine with some code that is used only on certain modules of my main application code and it's only required on certain files.
My custom engine is installed like this in Gemfile:
gem 'gem_name', require: false
and required in files like this:
require 'gem_name'
So, when i run rails s -e production (which has config.eager_load=true activated) it fails automatically with the following error
bootsnap/load_path_cache/core_ext/kernel_require.rb:58:in `load': No
such file to load (LoadError)
Any ideas on how to make eager_load work when a gem is not required on Gemfile?
gem 'gem_name', require: false
And what problems could i have if i set eager_load to false on production(like) environments?
I researched for a bit, try upating bootsnap gem, try delete 'bootsnap-load-path-cache' and 'bootsnap-compile-cache' from tmp/cache folder.
This article May help understand eager load https://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload/
This topic may help understand
What's the impact of eager_load=true?
it points to other solution, not require but autoload(http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html)
From the guides(please read):
https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoload-paths-and-eager-load-paths
For those that need to autoload all files inside a directory instead of requiring them, you can do this:
Dir.glob(File.join(some_path, 'lib', 'extensions', '*.rb')).map do |file|
autoload File.basename(file).gsub('.rb', '').classify.to_sym, file
end
instead of the classic
Dir[File.join(some_path, 'lib', 'extensions', '*.rb')].each do |f|
require f
end

Rails 3.2.8 - not loading assets (development)

I have searched around and can't rectify the situation based on the responses to other similar questions. I seem to have broken the asset pipeline somehow but can't seem to figure out how.
None of my assets are being loaded at all; rails seems to just be ignoring my manifest files. When I inspect my page in firebug, only the 'non-compiled' text inside my manifest files (both js and css) is being displayed - almost as if the asset pipeline wasn't even enabled.
I deleted the contents of public/assets since I was adding a new file to the manifest which seemed to start this behavior.
Current configuration:
environments/development.rb
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
application.rb
# Enable the asset pipeline
config.assets.enabled = true
config.assets.manifest = config.root
# Add extra assets for precompiling
config.assets.precompile += ['admin.js', 'admin.css']
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
I had the same issue. You can still use Ruby 2.1.2, just upgrade rails to latest 3.2.x version - it's 3.2.22
Gemfile:
gem 'rails', '3.2.22'
And run:
$ bundle update rails
The issue was caused by using an incompatible version of ruby. I was using version 2.1.2 which lead to unusual behavior from the sprockets gem (which powers the asset pipeline). This was fixed by downgrading to ruby 1.9.3. I haven't done any experimentation for fear of breaking it again but maybe this has been addressed in later versions of sprockets. I am using sprockets 2.1.3.
See: Rails 3.2.8 Application.js and Application.css are not working as expcted
Always remember two things when you want to handle Rails asset pipleline:-
if you want all you newly created js/css to autoinclude in application.js/css,pls add them in...
ELSE
IF you dont wont to add in manifest file(application.js/css) then use precompile directive in yuur environment file.
config.assets.precompile=%w(custom.css,custom2.js...etc)
so make sure you have either of these...
===========for example=-=============
suppose you have new css/js file:-
custom.css inside
app/assets/stylesheets/
so you can include in
application.css
// = require 'custom'
OR
use precompile directive:-
config.assets.precompile += %w( custom.css )
and then reference it like you always do
stylesheet_link_tag "custom"
same applies for js also
I just spent a few hours troubleshooting this issue (in 2017!) and it turned out I just needed to remove the gem active_reload. Updating rails and ruby was having no effect for me. The thread where I found that gold is here:
https://github.com/rails/rails/issues/2715

Disable Sprockets asset caching in development on Rails 4

Another question "Disable Sprockets asset caching in development" addresses how to disable Sprockets caching in Rails 3.2. How do you do the same thing on Rails 4? I am working on a gem that is deep in the asset pipeline and having to clear tmp/cache/* and restart Rails is getting tiring.
If you look at the Sprockets source, you can see that if cache_classes is true then app.assets gets set to app.assets.index, and the filesystem is no longer checked.
In order to get around this in development, you can add something similar to the following to your development.rb configuration:
# Sprockets configuration: prevent sprockets from caching assets in development
# when cache_classes is set to true
sprockets_env = nil
config.assets.configure do |env|
sprockets_env = env
# Sprockets environment configuration goes here
# env.js_compressor = :uglifier # or :closure, :yui
# env.css_compressor = :sass # or :yui
end
if config.cache_classes
config.after_initialize do
Rails.application.assets = sprockets_env
end
end
This essentially grabs a reverence to the Sprockets::Environment object before it is overwritten by the Sprockets::Index one, and allows the filesystem to be checked for new assets even when cache_classes is true. This seems to work for us in development, so hopefully it helps someone else out as well.

Cannot generate a Pages controller in the Rails 3 tutorial

I am working through the Michael Hartl Rails 3 tutorial, and I am currently on Chapter 3. The tutorial asks me to generate a Pages controller with actions for a Home page and a Contact page using the command line: "$ rails generate controller Pages home contact".
This is the output I get:
ruby 1.9.2p290 (2011-07-09) [i386-mingw32]
C:\Users\abcd\rails_projects2\sample_app>rails generate controller Pages home
contact
C:/Users/abcd/rails_projects2/sample_app/config/application.rb:8:in `require':
no such file to load -- sprockets/railtie (LoadError)
from C:/Users/abcd/rails_projects2/sample_app/config/application.rb:8:
in `<top (required)>'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.9/lib/rails/comman
ds.rb:15:in `require'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.9/lib/rails/comman
ds.rb:15:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
The contents of my config/application.rb file:
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module SampleApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
end
end
I have also discovered that when I try to run the command line "rails server", I get a similar error message. I don't know if this information is useful.
Thank you!
It looks like the tutorial is using Rails 3.0.9, but you've created your application using a later version of the Rails gem.
sprockets was added in version 3.1. Even though you've updated your Gemfile to specify Rails 3.0.9, the code that was generated when you ran rails new sample_app is expecting Rails 3.1 gems to be available (i.e. simply changing the Gemfile isn't enough to change the Rails version of the application).
You could try simply commenting out the reference to sprockets in your application.rb file, but even if that works for now it's likely there'll be other differences that'll cause errors later.
Your best bet is probably to start from scratch, but make sure you're using Rails 3.0.9. If you're using RVM, you could create a new gemset and install 3.0.9 into it, then use that gemset.
Alternatively, when you create the application specify the version of the gem you want in the command:
rails _3.0.9_ new sample_app
If you use this second method, then after you've created the application, simply using rails by itself to issue commands (like generate) should be okay, as Rails does some magic to determine the version of the app and use the right gem version, even if a later version is installed - you don't need to use rails _3.0.9_ all the time.
in your config/application.rb file, try to uncomment the "sprockets" line like this:
# require "sprockets/railtie"
Then check if it works afterwards... that should do the trick...
But if not, please check your Gemfile, it should look something like this:
# gem "rails", "~> 3.1.0" # or "3.0.9"
gem "rails" , "3.0.9"
gem 'sqlite3', '1.3.3' # or whatever DB you use
If that still doesn't help, check which version of sprockets you have installed:
in a shell, do a:
$ gem list | grep sprock
sprockets (2.0.0.beta.10)

Remove ActiveRecord in Rails 3

Now that Rails 3 beta is out, I thought I'd have a look at rewriting an app I have just started work on in Rails 3 beta, both to get a feel for it and get a bit of a head-start. The app uses MongoDB and MongoMapper for all of its models and therefore has no need for ActiveRecord. In the previous version, I am unloading activerecord in the following way:
config.frameworks -= [ :active_record ] # inside environment.rb
In the latest version this does not work - it just throws an error:
/Library/Ruby/Gems/1.8/gems/railties-3.0.0.beta/lib/rails/configuration.rb:126:in
`frameworks': config.frameworks in no longer supported. See the generated
config/boot.rb for steps on how to limit the frameworks that will be loaded
(RuntimeError)
from *snip*
Of course, I have looked at the boot.rb as it suggested, but as far as I can see, there is no clue here as to how I might go about unloading AR. The reason I need to do this is because not only is it silly to be loading something I don't want, but it is complaining about its inability to make a DB connection even when I try to run a generator for a controller. This is because I've wiped database.yml and replaced it with connection details for MongoDB in order to use this gist for using database.yml for MongoDB connection details. Not sure why it needs to be able to initiate a DB connection at all just to generate a controller anyway....
Is anyone aware of the correct Rails 3 way of doing this?
I'm going by this from reading the source, so let me know if it actually worked. :)
The rails command that generates the application template now has an option -O, which tells it to skip ActiveRecord.
If you don't feel like rerunning rails, you should check the following in your existing app:
Check that your config/application.rb doesn't have require 'rails/all' or require "active_record/railtie". Instead, for a standard Rails setup without ActiveRecord, it should have only the following requires:
require File.expand_path('../boot', __FILE__)
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"
require "sprockets/railtie"
# Auto-require default libraries and those for the current Rails environment.
Bundler.require :default, Rails.env
If, in config/application.rb, you are using the config.generators section, make sure it doesn't have the line g.orm :active_record. You can set this explicitly to nil, if you want, but this should be the default when g.orm is completely omitted.
Optional, but in your Gemfile, remove the gem line that loads the module for your database. This could be the line gem "mysql" for example.
Rails 4
I was looking for how to disable it in rails 4 and only found this answer which no longer works in rails 4. So this is how you can do it in rails 4 (tested in RC1).
In a new project
rails new YourProject --skip-active-record
In an existing project
In your Gemfile, remove the database driver gem, e.g. gem 'sqlite3' or gem 'pg'.
In config/application.rb, replace require 'rails/all' with
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
In config/environments/development.rb, remove or comment out config.active_record.migration_error = :page_load
Potentially you have to remove active_record helpers from the spec_helper (via VenoM in the comments)
Potentially you have to remove the ConnectionManagement middleware (seems to be the case with unicorn): config.app_middleware.delete "ActiveRecord::ConnectionAdapters::ConnectionManagement" (via https://stackoverflow.com/a/18087332/764342)
I hope this helps others looking for how to disable ActiveRecord in Rails 4.
For a new rails app, you can have it exclude active record by specifying the --skip-active-record parameter. Eg:
rails new appname --skip-active-record
If you generated a new project using Rails 3.2, you will also need to comment out:
config.active_record.mass_assignment_sanitizer = :strict
and
config.active_record.auto_explain_threshold_in_seconds = 0.5
in your development.rb file.
All of the above are true. The one more thing which I had to do in rails 3.1 is to comment out
config.active_record.identity_map = true
in config/application.rb.
If you're running rspec, you also need to remove (in spec_helper):
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
and remove
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
Also comment out
# config/application.rb
config.active_record.whitelist_attributes = true
(noted on rails 3.2.13)

Resources