Why is Rails not caching SQL queries? - sql

According to the Rails Guides:
Query caching is a Rails feature that caches the result set returned
by each query so that if Rails encounters the same query again for
that request, it will use the cached result set as opposed to running
the query against the database again.
Then follows an example where the same query is executed within a controller's action:
class ProductsController < ApplicationController
def index
# Run a find query
#products = Product.all
...
# Run the same query again
#products = Product.all
end
end
In my view layout at several places I call Category.pluck(:id). In the development log I then see this line several times:
SELECT "categories"."id" FROM "categories"
This happens even if I set this: config.action_controller.perform_caching = true for development. Why is this happening?

The query cache come from Rack.
Run rake middleware
And look for ActiveRecord::QueryCache
If thats in your middleware, SQL caching should be enabled, unless something else is turning it off.
Here is some documentation on the query cache:
http://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/QueryCache.html
And the Rack code
http://api.rubyonrails.org/classes/ActiveRecord/QueryCache.html

Related

How to refresh Rails / Sprockets to be aware of new manifest on production server after assets:precompile

We have a use case where we need to run assets:precompile outside of the deploy/restart process, and therefore preferably without having to restart the Rails server processes. Is this possible in a Passenger environment?
I've been banging my head trying a bunch of stuff within Rake tasks and fiddling with Rails.application.config.assets stuff, but nothing makes the application pickup the changes to the digests except restarting Passenger with /usr/bin/env touch ~/project/current/tmp/restart.txt
We ended up going with a 2 part solution:
Part 1 is to setup the app to hit redis to store an 'assets:version' (we just went with a timestamp). Then, whenever our process was done precompiling, we update this assets version with the latest timestamp.
Part 2 was that we added a before_filter :check_assets_version in our main application_controller that all our other controllers inherit from. This method looks something like this:
def check_assets_version
##version ||= 1
latest_version = get_assets_version # wrapped call to redis to get latest version
# clear assets cache if current version isn't the same as the latest version from redis
unless latest_version.blank? || latest_version.to_s == ##version
##version = latest_version
if Rails.env.production? || Rails.env.sandbox? || Rails.env.experimental?
nondev_reset_sprockets
else
dev_reset_sprockets ##version
end
end
end
And those two reset methods look like this:
def nondev_reset_sprockets
manifest = YAML.load(File.read(Rails.root.join("public","assets","manifest.yml")))
manifest.each do |key, value|
Rails.application.config.assets.digests[key] = value
end
end
The nondev reset "stuffs" each of the values into memory from the new generated manifest file
def dev_reset_sprockets(version)
environment = Rails.application.assets
environment = environment.instance_variable_get('#environment') if environment.is_a?(Sprockets::Index)
environment.version = version
end
The dev reset just kicks sprockets "version" value so that it thinks (correctly so) it needs to reparse and live recompile the latest assets.
Another way of updating the assets in production is as follows:
Rails.application.assets_manifest.instance_eval do
new_manifest = Sprockets::Manifest.new(manifest.dir, manifest.filename)
#data = new_manifest.instance_variable_get(:#data)
end
For Rails 4 (Sprockets 2.11), you can do:
Rails.application.assets_manifest = Sprockets::Manifest.new(Rails.env, Rails.application.assets_manifest.path)
# see sprockets-rails/lib/railtie.rb
ActionView::Base.assets_manifest = Rails.application.assets_manifest

rails: resque worker log doesn't honor log_tags

I have the following line in my config/environments/development.rb:
config.log_tags = [lambda { |req| Time.now }]
which works perfectly for the rails log (it prepends every entry with a timestamp).
I'd like to have the same behaviour in my resque workers.
The output of
p Rails.application.config.log_tags
in a resque job's perform method shows me, that there is a proc in it:
[#<Proc:0x007ffb36c14920#/.../config/environments/development.rb:49 (lambda)>]
But still, the log entries don't have timestamps.
I'm running out of ideas on why this happens...
Log tags are evaluated once per request in Rack middleware (Rails::Rack::Logger#call). There is no Web request when Resque runs and so you see nothing.
To get what you want, you should add code similar to Rails::Rack::Logger#compute_tags to Resque as a job hook, e.g., in before_perform.

Retrieving sql queries from Active-record queries in Rails 3

How do I trace which SQL query did my Activerecord methods generated (eg find, where).
You can debug ActiveRecord queries from a console.
Hit rails console and enter:
ActiveRecord::Base.logger = Logger.new(STDOUT)
I assume you're using Rails 3.0.x, you can do that by configuring your active record. Put this in config/environments/development.rb
# Log ActiveRecord
ActiveRecord::Base.logger = Logger.new(STDOUT) if defined?
Rails::Console
Now, every query is explained in console.
You can call to_sql on relation objects (like that returned when you call where) to get the SQL for those queries.
If you want to do it permanently (always show queries in console) just add those files:
~/.rvmrc
railsrc_path = File.expand_path('~/.railsrc')
if ( ENV['RAILS_ENV'] || defined? Rails ) && File.exist?( railsrc_path )
begin
load railsrc_path
rescue Exception
warn "Could not load: #{ railsrc_path }" # because of $!.message
end
end
~/.railsrc
require 'active_record'
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.clear_active_connections!

Disable Rails SQL logging in console

Is there a way to disable SQL query logging when I'm executing commands in the console? Ideally, it would be great if I can just disable it and re-enable it with a command in the console.
I'm trying to debug something and using "puts" to print out some relevant data. However, the sql query output is making it hard to read.
Edit:
I found another solution, since setting the logger to nil sometimes raised an error, if something other than my code tried to call logger.warn
Instead of setting the logger to nil you can set the level of the logger to 1.
ActiveRecord::Base.logger.level = 1 # or Logger::INFO
To turn it off:
old_logger = ActiveRecord::Base.logger
ActiveRecord::Base.logger = nil
To turn it back on:
ActiveRecord::Base.logger = old_logger
This might not be a suitable solution for the console, but Rails has a method for this problem: Logger#silence
ActiveRecord::Base.logger.silence do
# the stuff you want to be silenced
end
Here's a variation I consider somewhat cleaner, that still allows potential other logging from AR. In config/environments/development.rb :
config.after_initialize do
ActiveRecord::Base.logger = Rails.logger.clone
ActiveRecord::Base.logger.level = Logger::INFO
end
For Rails 4 you can put the following in an environment file:
# /config/environments/development.rb
config.active_record.logger = nil
In case someone wants to actually knock out SQL statement logging (without changing logging level, and while keeping the logging from their AR models):
The line that writes to the log (in Rails 3.2.16, anyway) is the call to debug in lib/active_record/log_subscriber.rb:50.
That debug method is defined by ActiveSupport::LogSubscriber.
So we can knock out the logging by overwriting it like so:
module ActiveSupport
class LogSubscriber
def debug(*args, &block)
end
end
end
I used this: config.log_level = :info
edit-in config/environments/performance.rb
Working great for me, rejecting SQL output, and show only rendering and important info.
In Rails 3.2 I'm doing something like this in config/environment/development.rb:
module MyApp
class Application < Rails::Application
console do
ActiveRecord::Base.logger = Logger.new( Rails.root.join("log", "development.log") )
end
end
end
Just as an FYI, in Rails 2 you can do
ActiveRecord::Base.silence { <code you don't want to log goes here> }
Obviously the curly braces could be replaced with a do end block if you wanted.
I use activerecord 6.0.3.3 and I had to include ActiveSupport::LoggerSilence
include ActiveSupport::LoggerSilence
ActiveSupport::LoggerSilence.silence do
## everything you want to silence
end
This however did not work with anything related to creating or deleting SQL tables like ActiveRecord::Migration.drop_table. For this to be silenced I added:
ActiveRecord::Schema.verbose = false
I had to solve this for ActiveRecord 6, and I based my answer on fakeleft's response, but it wasn't quite right, since it was suppressing other logging such as the logging of nested views. What I did was created config/initializers/activerecord_logger.rb:
# Suppress SQL statement logging if necessary
# This is a dirty, dirty trick, but it works:
if ENV["ACTIVERECORD_HIDE_SQL"].present?
module ActiveRecord
class LogSubscriber
def sql(event)
end
end
end
end
The log subscriber in AR 6 has a sql event that we want to hide, so this is very narrowly targeted to skip that event.

How to erase SQL queries from ActiveRecord::Base.logger

I'm developing an application using Ruby on Rails.
I would like to erase old queries in the ActiveRecord::Base.logger object every time when I call a new action, essentially where ENV = production.
The goal is not to erase all queries like using config.log_level :info. I need only last queries to build a file with those queries.
Here is some code:
in the lib:
module SqlHunter
class ActiveRecord::ConnectionAdapters::AbstractAdapter
##queries = [] # without this line it work perfectly
##logging = false
cattr_accessor :queries, :logging
def log_info_with_trace(sql, name, runtime)
##queries << sql if ##logging
end
alias_method_chain :log_info, :trace
end
end
in the controller (report action)
ActiveRecord::ConnectionAdapters::AbstractAdapter::logging = true
.....
sqlfile = File.open("public/advancedStats/#{#dir_name}/advancedStatQuery.sql", 'w')
#queries = ActiveRecord::ConnectionAdapters::AbstractAdapter::queries
for query in #queries do
sqlfile.write("#{query} \n")
end
sqlfile.close
I asked an old related question here
link text
Thanks to Tamás Mezei and Damien MATHIEU for their last answer
Mondher
So you want to filter the SQL queries in production mode or am I missing the point?
If it's about just filtering, prod mode will automatically filter sql queries. If you'd like to filter when developing, edit the config/environments/development.rb file and insert
config.log_level = :info
Essentially, it will filter SQL with all the other stuff that's below info level (debug stuff).
If you want some more sophisticated solution, you can always exend/override the AbstractAdapter class in
RUBY_HOME/lib/gems/1.8/gems/activerecord-nnn/active_record/connection_adapters/abstract_adapter.rb