Reload namespaced constant in initializer - ruby-on-rails

Ran into an interesting scenario today that I'm unsure how to resolve.
Given a rails app with an initializer:
file: config/initializers/integrations.rb
Integrations::CONFIGS = { "key" => "value" }.freeze
If I go into bundle exec rails console and ask for that constant it works as expected:
Integrations::CONFIGS
=> {"key"=> "value"}
Then if I use reload! in the console, I lose that constant:
[2] pry(main)> reload!
Reloading...
=> true
[3] pry(main)> Integrations::CONFIGS
NameError: uninitialized constant Integrations::CONFIGS
from (pry):3:in `<main>'
If I remove the namespace and just have CONFIGS as a constant it works and reloads as expected. I've read through as much of the reload! documentation as I could find and from what I can tell this isn't expected.
My question being, how can I correctly use a namespaced constant in an initializer while also still being able to use reload!?

Related

Use ActiveSupport::Cache::FileStore directly in a model class

I tried to use ActiveSupport::Cache::FileStore dirctly in a model class:
#backend_cache = ActiveSupport::Cache::FileCache.new Rails.root.join("tmp", "cache")
The program reports a NameError
NameError: uninitialized constant ActiveSupport::Cache::FileCache
Did you mean? FileTest
I added
require "active_support"
require "active_support/core_ext"
It still shows the error. I know that I can use Rails.Cache for the purpose, but the object I cached must be on the disk, which is different from other parts of the application.
The application is written in Rails 6.
I tried this inside a rails 6 console and it works just fine.
#backend_cache = ActiveSupport::Cache::FileStore.new(Rails.root.join("tmp", "cache"))
#backend_cache.write('x', 1) # => true
#backend_cache.read('x') # => 1
It's just typo I mentioned in the comment. It's ::FileStore.new instead of ::FileCache.new

Ruby on Rails: Configure API in initializer in development

I have a Ruby on Rails app with an API in lib. Files in lib are autoloaded, and the API is configured in an initializer.
# lib/my_api.rb
module MyApi
extend Configuration
end
# lib/my_api/configuration.rb
module MyApi
module Configuration
attr_accessor :my_setting
def configure
yield self
end
end
end
# config/initializers/my_api.rb
MyApi.configure do |config|
config.my_setting = 'foo'
end
This works in production, but in development the API gets configured when the server is started. After I change some code, the configuration is lost and there are errors because the settings are nil:
irb(main):001:0> MyApi.my_setting
=> "foo"
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> MyApi.my_setting
=> nil
My guess is that in development, the classes are reloaded, but the initializer is not, which means it only gets configured once after starting the server.
Right now I'm duplicating my configuration in lib/my_api.rb, but that's very hacky.
What's a clean solution for this problem?
module MyApi
module Configuration
mattr_accessor :my_setting
def configure
yield self
end
end
end
mattr_accessor is an ActiveSupport macro for creating module level accessors.
Well, until someone comes up with a better solution, I've come up with two workarounds. I went with 2.
Don't autoload the lib directory (meaning don't autoload the API). That means having to restart the server when the API code changes, but solves the problem. That's why configuring gems like this works -- because they aren't autoloaded.
Manually reload the initializer in development at the end of lib/my_api.rb:
load Rails.root.join('config/initializers/smart_meter.rb') if Rails.env.development?
The MyApi constant will be replaced by a new one when Rails autoloads classes. The configuration is still available on the old object:
Loading development environment (Rails 4.2.0)
irb: warn: can't alias context from irb_context.
irb(main):001:0> MyApi.my_setting
=> "foo"
irb(main):002:0> OldMyApi = MyApi
=> MyApi
irb(main):003:0> reload!
Reloading...
=> true
irb(main):004:0> MyApi.my_setting
=> nil
irb(main):005:0> OldMyApi.my_setting
=> "foo"
irb(main):006:0> load Rails.root.join('config/initializers/smart_meter.rb')
=> true
irb(main):007:0> MyApi.my_setting
=> "foo"

Httparty in rails

I am trying to learn how to use httparty. I ran 'gem install httparty', first in my terminal, expecting to be able to use it in a pry session but no luck.
Next, I created a new rails app, added the gem to my gem file and ran bundle and in a pry session tried to use httparty as follows:
[1] pry(main)> HTTParty.get("http://rubygems.org/api/v1/versions/httparty.json")
NameError: uninitialized constant HTTParty
from (pry):1:in `__pry__'
[2] pry(main)> HTTParty.get("http://rubygems.org/api/v1/versions/httparty.json)
[2] pry(main)* httParty.get("http://rubygems.org/api/v1/versions/httparty.json)
SyntaxError: unexpected tIDENTIFIER, expecting ')'
httParty.get("http://rubygems.org/api/v1/versions/httparty.json)
^
[2] pry(main)> httParty.get("http://rubygems.org/api/v1/versions/httparty.json")
NameError: undefined local variable or method `httParty' for main:Object
from (pry):2:in `__pry__'
[3] pry(main)> response = httParty.get("http://rubygems.org/api/v1/versions/httparty.json")
NameError: undefined local variable or method `httParty' for main:Object
from (pry):3:in `__pry__'
[4] pry(main)> response = HTTParty.get('https://api.stackexchange.com/2.2/questions?site=stackoverflow')
NameError: uninitialized constant HTTParty
from (pry):4:in `__pry__'
Any help would be much appreciated. Thank you
require the gem, either in your pry invocation
pry -rhttparty
or once in pry
require 'httparty'
I am working on the exact same thing right now. What I did was create a file test_party.rb in the rails lib directory. (Make sure to add config.autoload_paths += %W(#{config.root}/lib) to your config/application.rb
In the new lib file create a class TestParty and include HTTParty
Then in rails console you can run TestParty.whatever_you_want
Hope that helps!

Error using Log4r

I have a problem using Log4r.
uninitialized constant Log4r::Logger::RootLogger
I tried this, but still got an error:
>> require "log4r"
=> true
>> Log4r::DEBUG
NameError: uninitialized constant Log4r::DEBUG
>> Log4r::Logger.root
=> uninitialized constant Log4r::Logger::RootLogger
from /var/lib/gems/1.9.1/gems/log4r-1.1.11/lib/log4r/staticlogger.rb:5:in `root'
from (irb):5
from /usr/bin/irb:12:in `<main>'
Your problem with Log4r::Logger.root is version depending (the actual version 1.1.11 has this problem).
You may use the previous log4r-version 1.1.10:
gem 'log4r', '<=1.1.10' #or '= 1.1.10'
require 'log4r'
Log4r::Logger.root
log4r defines the constants like Log4r::DEBUG with the creation of the first logger.
You need a Log4r::Logger.new('dummy') before you have access to the level constants.
require 'log4r'
p defined? Log4r::INFO #false
Log4r::Logger.new('dummy')
p defined? Log4r::INFO #constant -> is defined
Some background:
There is a constant Log4r::Log4rConfig::LogLevels defining the different levels. The level-constants are defined, when the first logger is created. You may define them also with Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
This technique allows it to create loggers with different logging levels.
AlthoughLog4r::Logger.root no longer enables the constants, the code included later on in the answer you referred to does introduce the constants:
Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
per the following:
MacbookAir1:so1 palfvin$ irb
2.0.0p247 :001 > require 'log4r'
=> true
2.0.0p247 :002 > Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
=> 5
2.0.0p247 :003 > Log4r::DEBUG
=> 1
2.0.0p247 :004 >

Rails 3.2.8, heroku: uninitialized constant Less::Engine

I am seeing this error in a delayed job on heroku and it makes no sense to me:
{uninitialized constant Less::Engine
(in /app/app/assets/stylesheets/share_and_earn_recommendation_email.css.less)
/app/vendor/bundle/ruby/1.9.1/gems/tilt-1.3.3/lib/tilt/css.rb:60:in `prepare'
...
Why no sense? Because css.rb looks like this:
def prepare
if ::Less.const_defined? :Engine
#engine = ::Less::Engine.new(data) # line 60
else
...
Which means it is impossible to hit line 60 if Less::Engine is undefined. What am I missing?
EDIT
Even better demonstration from heroku console:
irb(main):008:0> ::Less.const_defined? :Engine
=> true
irb(main):009:0> ::Less::Engine
NameError: uninitialized constant Less::Engine
EDIT 2
It gets more interesting:
irb(main):011:0> ::Less.const_defined? :Engine, false
=> false
The difference is that the latter does not search ancestors. But there are no ancestors, so it should not make a difference:
irb(main):012:0> ::Less.ancestors
=> [Less]
If you just recently upgraded your rails version within the 3.2.x stack you will find that less is "present" in earlier versions like 3.2.2 and absent in later versions like 3.2.9.
I haven't fully investigated the issue, but I noticed when I went to upgrade from 3.2.2 to 3.2.9, I got some "less" issues.
Cheers

Resources