Why the Rails.cache.read can't get anything in ApplicationController? - ruby-on-rails

I have a problem with my Ruby on rails application. The Ruby on Rails Cache in ApplicationController.
The data can't get, but it exists.
class ApplicationController < ActionController::Base
before_filter :init
def init
#setting = Rails.cache.read("data/setting")
if not #setting
#setting = Setting.find_create
Rails.cache.write("data/setting",#setting)
end
end
end
Development.log show this:
Cache read: data/setting
Setting Load (0.5ms) SELECT * FROM > "settings" LIMIT 1
Cache write: data/setting
Why is this happening?

If you are running your app in development mode, it's likely that caching is turned off. Check your config/development.rb file for the following:
config.action_controller.perform_caching = false
To test your caching you can either change this value to true, or run in a different environment where caching is turned on. I often create an environment development_as_production, pointing at the development db, but with my production.rb settings.

I am Json, I was changed the name.
But the development environment setting current is:
config.action_controller.perform_caching = true
The perform_caching was trun on!
The others caches can working. only this cache didn't working (It's in the ApplicationController).
#setting = Rails.cache.read("data/setting")
if not #setting
#setting = Setting.find_create
Rails.cache.write("data/setting",#setting)
end
Why? Is Rails.cache.read can't working in the ApplicationController?

Related

Rails - conditionally log for a specific hostname

I'm looking for a way to configure a Rails server log only if the client has contacted a specific hostname. e.g. I could make it so that http://public.example.com doesn't get logged, but http://debug.example.com (same underlying Rails app server) does get logged (or ideally gets logged in more detail than the regular host). It would help with production debugging.
You can use gem Lograge to customize your log. This gem will give you much more custom to your log. For example, in your case, I will do this
After install the gem. Create a file at config/initializers/lograge.rb
# config/initializers/lograge.rb
Rails.application.configure do
config.lograge.enabled = true
config.lograge.custom_options = lambda do |event|
# custom log on specific domain
if event.payload[:host] == "debug.example.com"
{:host => event.payload[:host]}
else
{}
end
end
end
And in your Application Controller
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# This will add request's host to lograge so you can use it to filter log later
def append_info_to_payload(payload)
super
payload[:host] = request.host
end
end
Now you can customize your log base on domain, on how to customize it please read at: https://github.com/roidrage/lograge

"Unable to autoload constant User" error when changed code in development

I have a problem with my rails application. After an Update from Rails 3 to 4.
When I surf through the pages after starting the server in development mode everything is fine.
But after a single code change (even adding a space) every page request shows the following error.
Unable to autoload constant User, expected
/path/to/my/rails-app/app/models/user.rb to define it
The file lives exactly there and defines the class:
class User < ActiveRecord::Base
…
I tried many things with config.autoload_paths and config.eager_load_paths in application.rb but with no luck.
Deactivating spring did not help either.
Developing an app and having to restart the server after every single change seems so 90s.
$ rails -v
Rails 4.2.4
$ ruby -v
ruby 2.1.7p400 (2015-08-18 revision 51632) [x86_64-linux]
Some relevant configs:
development.rb
MyApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = {
host: 'localhost',
port: 3000
}
end
application.rb
module Serviceportal
class Application < Rails::Application
# 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'
[… some asset precompile stuff …]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = 'utf-8'
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/app/mailers",
"#{config.root}/app/controllers/concerns",
"#{config.root}/app/models/concerns",
"#{config.root}/app/decorators/concerns",
"#{config.root}/lib",
"#{config.root}/lib/shared"
]
config.eager_load_paths += Dir["#{config.root}/app/mailers",
"#{config.root}/app/controllers/concerns",
"#{config.root}/app/models/concerns",
"#{config.root}/app/decorators/concerns",
"#{config.root}/lib",
"#{config.root}/lib/shared"]
# 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 = 'Berlin'
# 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
[… some SQL and active support stuff …]
config.action_controller.include_all_helpers = false
config.action_controller.action_on_unpermitted_parameters = :raise
# Do not swallow errors in after_commit/after_rollback callbacks.
config.active_record.raise_in_transactional_callbacks = true
end
end
Edit: The error mostly shows up in lib/auth/user_proxy.rb in the following function. Maybe this helps to narrow the range of possible causes.
def self.usertype_allowed?(type)
[ User, TempCustomer ].include? type.classify.safe_constantize rescue false
end
Edit 2: Stringify the class names in Edit 1 helped (thanks #Benjamin Sinclaire). But only leads to the next errors. I could also avoid using classes. But at the following error in app/controllers/concerns/security.rb there is nothing can change?
Unable to autoload constant User, expected
/path/to/my/rails-app/app/models/user.rb to define it
code:
def set_current_user
User.current = current_user
end
with current user saved in the Thread (code from /path/to/my/rails-app/app/models/user.rb
def self.current
Thread.current['current_user']
end
def self.current=(user)
Thread.current['current_user'] = user
end
Just to make it clear again: It works after server restart in development until I change some code somewhere.
1 See if you have any multiple-level class or module declaration done one one line and change them to be declared in several lines.
Instead of
class Parent::Sub::Child
end
Do
module Parent
module Sub
class Child
end
end
end
2 Check your model association definitions, and ensure you are never using constant. Use string instead.
Instead of
belongs_to :manager, class_name: User
Do
belongs_to :manager, class_name: 'User'
3 Just saw your edit. Can you refactor like this?
# I assume `type` is a string or such, so we can compare classes
# names instead of constants, and get rid of `safe_constantize`
def self.usertype_allowed?(type)
['User', 'TempCustomer'].include? type.classify rescue false
end
4 Not a good idea to serialize an active record object in the Thread storage. Change it to store the user id instead, like this:
def set_current_user
User.current = current_user.id
end
def self.current
Thread.current['current_user_id']
end
def self.current=(user_id)
Thread.current['current_user_id'] = user_id
end
You don't need include app/models/concerns and app/controllers/concerns in your autoload/ eagerload paths as they are included by default in Rails 4: https://signalvnoise.com/posts/3372-put-chubby-models-on-a-diet-with-concerns
Also make sure that your concerns are defined as modules, extend ActiveSupport::Concern and with the appropriate file name
#taggable.rb
module Taggable
extend ActiveSupport::Concern
end
Another cause of your problem might be that some modules/ classes in app/decorators/concerns, lib, lib/shared are using the User class
which is not loaded yet or some of it's dependencies are not loaded so try adding require_relative path_to_user.rb at the top of those files
-----Edit-------
Try adding at the top of lib/auth/user_proxy.rb
require_dependency 'app/models/user'
This way you'll remove any ambiguity in autoloading the User class and you won't mess around with Rails autoloading see more here: http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#require-dependency , http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#common-gotchas
Same problem but in an engine w/ namespaces. No issues in production or in development until a code-change / autoload.
The solution was to
checking for double definitions (there were none)
checking if the module nesting strictly follows rails conventions in the filesystem.
I've had myns under myengine/app/myns/subns/obj.rb but myns is being ignored as it is at the root of the app folder, so moving the myns folder into a subfolder myengine/app/lib/myns solved the issue.
Note: the rails error message was very explicit about the module nesting (while still pointing to the wrong .rb file in the filesystem) so look closely at the error. The error was 'Unable to autoload constant subns/obj.rb in .../myns/subns/obj.rb'. Rails suggesting the incorrect file-location (which exists) is misleading in this case.
During a Rails/Ruby Update I found time to look into this and finally found the cause.
The user class had an unloadable in it for years. That caused the problems since Rails 4. Now I removed this and found no issues after that.

Rails.cache.fetch caching in development

Using Rails.cache.fetch like below is caching even in my development environment (with caching turned off):
#boat_features = Rails.cache.fetch("boat_features", expires_in: 10.minutes) do
BoatFeature.all
end
Has anyone run into this before?
That's normal. That sort of caching isn't turned off in development. In a previous app where this was a problem we used the memory store and then added a middleware that did Rails.cache.clear after every request.
Something like
config.middleware.use ClearCache
in development.rb
and then your ClearCache middleware should look something like
class ClearCache
def initialize(app)
#app = app
end
def call(env)
#app.call(env)
ensure
Rails.cache.clear
end
end
In Rails 3.2 there's also ActiveSupport::Cache::NullStore
I had the same problem. I worked around a lot then came up with this simple solution. In your development configuration file config/environments/development.rb add these settings
config.perform_caching = false
config.cache_store = :null_store

Rails 2.3.2 and SHOW TABLES

I have annoying problem with SHOW TABLES in my Rails 2.3.2 APP - it is slowing my APP very deep. The question is, how to get rid of SHOW TABLES usage and where it is used in Rails framework? From APP logs I can see that it is being used all the time.
Thank you!
config/environments/production.rb:
config.cache_classes = true
config.action_controller.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
"SHOW TABLES" is ORM-dependent SQL query, it fires with every action to provide classes reload in development mode. How much time does the query take?
I was seeing a similar problem in Rails 3.0 and was able to fix it using the gist pointed to from this issue. Looks like it's fixed in Rails 3.2.
I added ar_patch.rb to config/initializers with this code:
unless Rails.env.development?
require "active_record/connection_adapters/mysql2_adapter"
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter < AbstractAdapter
extend ActiveSupport::Memoizable
memoize :tables, :pk_and_sequence_for, :columns
end
end
end
end

analytics if on production site, not a local or heroku subdomain

This question is about getting an analytics script to run in one of these three environments.
mysite.heroku.com
mysite-staging.heroku.com
mysite.com - this is the only one I want it to run on.
This is how I plan to lay it out, but any suggestions are welcome.
In my helper
def render_analytics
if local_request? || #on a Heroku subdomain
false
else
true
end
end
In my layout
<%= render 'shared/analytics' if render_analytics %>
render_analytics returns a boolean: true if on mysite.com, false if a local_request? or on a Heroku subdomain (ex: mysite.heroku.com || mysite-staging.heroku.com)
So how can I find out if it is coming from Heroku.
Use hostname:
if local_request? || `hostname` =~ /heroku/i
A cleaner solution is to set a constant in your environment during deployment that allows you to know whether you are on Heroku. As the Heroku deploy process is pretty opaque in terms of letting you dork around with config files, you might have your method memoize the result so you aren't doing a system call each time you render a view.
I just did something similar with a method that checks the database adapter to account for differences between my development environment and Heroku. Here's my lib/adapter.rb:
class Adapter
cattr_reader :adapter
def self.postgres?
##adapter ||= Rails.configuration.database_configuration[Rails.env]['adapter']
adapter == 'postgresql'
end
def self.mysql?
##adapter ||= Rails.configuration.database_configuration[Rails.env]['adapter']
adapter == 'mysql'
end
def self.sqlite?
##adapter ||= Rails.configuration.database_configuration[Rails.env]['adapter']
adapter.include?('sqlite')
end
end
Note that in addition to this, you have to change application.rb such that lib is added to your autoload path:
config.autoload_paths += Dir["#{config.root}/lib/**/"] # include all subdirectories

Resources