Rails precompile constant uninitialized - ruby-on-rails

I wanted to preload the configuration (from ".yml" files). In one of my initializer files (config/initializers/facebook.rb) I have following line of code:
FACEBOOK_CONFIG = YAML.load_file("#{Rails.root}/config/facebook.yml")[Rails.env]
So, it works like a charm in the "DEVELOPMENT" mode. Once I switch to the production mode, it keeps telling me, that FACEBOOK_CONFIG is an uninitialized constant for my "facebook.js.coffee.erb" file, located in assets/javascript (If it matters), if I want to o "rake assets:precompile". I've tried doing random stuff, like: RAILS_ENV=production bundle exec rake assets:precompile or
rake assets:precompile:all
, but no luck
I have tried assigning "initialize_on_precompile = true" variable for my production environment (although, it should be true by default), just in case.
Why it doesn't work in production mode (But, I want to emphasise, that it does work(!) in the development environment).
Can someone help with that one ?

I encountered exactly the same problem. This is because your javascript(coffescript) file makes reference to a constant that is defined in an initializer. Because it is precompiled before the initializer the app throws an error.
This is the simple solution I found. You place this code at the bottom of your application.rb file in config:
module AssetsInitializers
class Railtie < Rails::Railtie
initializer "assets_initializers.initialize_rails",
:group => :assets do |app|
require "#{Rails.root}/config/initializers/facebook.rb"
end
end
end
It manually loads up certain files from the initializer folder. It solved my problem.
Hopefully this was the issue for you as well.

module Rails
class << self
def facebook_config
##facebook_config ||= nil
end
def facebook_config=(facebook_config)
##facebook_config = facebook_config
end
end
end
Rails.facebook_config = YAML.load_file("#{Rails.root}/config/facebook.yml")[Rails.env]
# And you can use it like this in anywhere:
puts Rails.facebook_config

Related

Overriding const_missing returns `NameError uninitialized constant` in non-dev environments

I have the following code in my rails app
# app/models/test_module/text_class.rb
module TestModule
class TestClass
end
end
# app/models/test_module.rb
module TestModule
def self.const_missing(name)
super(delete_end_number(name.to_s).to_sym)
end
def self.delete_end_number(str)
str.gsub(/\d+$/,'')
end
end
When it runs in development it works
>> TestModule::TestClass1
=> TestModule::TestClass
When I run it in production however I get
NameError (uninitialized constant TestModule::TestClass)
If I just copy TestModule::TestClass into the console it works. It seems just to not work with the const_missing method.
I suspect it may have something to do with the autoloading as when I set config.cache_classes and config.eager_load to true in development.rb it happens there too. I can't seem to figure out how to get it to work in cached environments though.
Change from
super(delete_end_number(name.to_s).to_sym)
To
const = delete_end_number(name.to_s).to_sym
ActiveSupport::Dependencies.load_missing_constant(self, const)

Sprockets cache stopping changes to initializer config

I have a gem that I've been trying to make configurable. The goal is to have a config block in an initializers file that lets the developer customize the media_query breakpoints in the gems scss file.
My congiguration class looks like this
# my_gem/lib/my_gem/configuration.rb
module MyGem
class << self
attr_accessor :configuration
end
def self.configure
self.configuration ||= Configuration.new
yield(configuration)
end
class Configuration
attr_accessor :med_pixel_width, :lrg_pixel_width
def initialize
#med_pixel_width = 600
#lrg_pixel_width = 1024
end
end
end
I have created a generator that works fine rails g my_gemwhich creates the following initializer file with the cofig block
# config/initializers/my_gem.rb
MyGem.configure do |config|
config.med_pixel_width = 768
config.lrg_pixel_width = 1024
end
And then in my gems stylesheet I catch the configuration
# app/assets/stylesheets/my_gem/my_style.scss.erb
#media only screen and (min-width: <%= MyGem.configuration.med_pixel_width %>px ) {
.styles {
color: red;
}
}
After running bundle and including the gems css asset files in my test app's application.css I can see the styles in the browser being applied as expected. AND the configuration is working. BUT only on the first time the server is started. After I try to change the configuration again no changes take place.
I have discovered that sprockets being cached is the culprit. I confirmed by adding rake tmp:clear right above my config block and then all works whenever i restart the server I can see the changes taking place
# config/initializers/my_gem.rb
system `rake tmp:clear`
MyGem.configure do |config|
config.med_pixel_width = 768
config.lrg_pixel_width = 1024
end
My question is Is there some other simple solution I'm missing here? And if there's not ... is putting this rake tmp:clear in my initializer file bad practice? Would it potentially slow down the development environment workflow for developers using the gem?

Production uninitialized constant custom class stored in lib (heroku)

I have a custom class stored in /lib (/lib/buffer_app.rb):
require 'HTTParty'
class BufferApp
include HTTParty
base_uri 'https://api.bufferapp.com/1'
def initialize(token, id)
#token = token
#id = id
end
def create(text)
message_hash = {"text" => text, "profile_ids[]" => #id, "access_token" => #token}
response = BufferApp.post('/updates/create.json', :body => {"text" => text, "profile_ids[]" => #id, "access_token" => #token})
end
end
I'm attempting to use this this class in an Active Admin resource and get the following error when in production (Heroku):
NameError (uninitialized constant Admin::EventsController::BufferApp):
It's worth noting I have this line in my application.rb and that this functionality works locally in development:
config.autoload_paths += %W(#{Rails.root}/lib)
If I try include BufferApp or require 'BufferApp' that line itself causes an error. Am I having a namespace issue? Does this need to be a module? Or is it a simple configuration oversight?
I had exactly the same problem with Rails 5 alpha. To solve it, I had to manually require the file:
require 'buffer_app'
and not: (require 'BufferApp')
Even if Michal Szyndel's answer makes great sense to me, after manually requiring the file, prefixing :: to the constant was non influential in my case.
Anyway I am not satisfied with the manual requiring solution because I need to add code which is environment specific. Why don't I need to require the files manually in development?
Change this
config.autoload_paths += %W(#{Rails.root}/lib)
to this
config.eager_load_paths += %W(#{Rails.root}/lib)
eager_load_paths will get eagerly loaded in production and on-demand in development. Doing it this way, you don't need to require every file explicitly.
See more info on this answer.
Error line says it all, you should reference class as ::BufferApp

uninitialized constant ModelObserver - Rake task on Heroku

Rake task performs ActiveRecord model operations. I added ActiveRecord::Base in the rake task and that works locally, but not on Heroku resulting in this error:
uninitialized constant BookingObserver
on the line with ActiveRecord::Base. If I do not include that line then I cannot use the model at all (resulting in similar error just for the model not the observer).
Your rake task will need to load the Rails environment before executing ActiveRecord code.
# lib/tasks/my_tasks.rake
task :my_task => :environment do
# Your task here
# it has access to the Rails environment now
end
Also see this similar issue and the Railscast on custom rake tasks.
I was using config.threadsafe! which disables dependency loading (thus not loading the observer, just the model). The solution was to add config.dependency_loading = true if $rails_rake_task to the environment.
I was able to fix this issue by commenting out config.threadsafe! in production.rb.
I added this code in the application.rb
config.autoload_paths += Dir[ Rails.root.join('app', 'models', '**/') ]
just before calling:
config.active_record.observers = [:user_observer]
i think because my application, it doesnt automatically discovers the directory of my observers which is under models/observers/

Reload lib files without restart dev server in Rails 3.1

I have some modules inside the lib folder in rails i.e.:
/lib/myapp/lib/**
I am working on them in development, however each time I have to restart server. I have been through a number of different questions on SO but most of them are for not for rails 3.1
I currently have an initializer that does this;
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"], true) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/myapp/lib/*"], true) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
Is there a generic way to do this? Its very time consuming having to restart the server every single time!
Get rid of the initializer and in your application.rb file put following line:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
One thing to watch out is that your module and class names should follow the naming convention for autoreload to work. for example if you have file lib/myapp/cool.rb, then your constant for class/module declaration in cool.rb should look like this:
Myapp::Cool
If you have file lib/myapp/lib/cool.rb and you want it to use Cool as class/module name instead of Myapp::Lib::Cool then your autoload should look like this:
config.autoload_paths += Dir["#{config.root}/lib/myapp/lib/**/"]
As long as you are running in devmode, rails will automatically reload all classes/modules that are in autoload path and follow naming conventions.
Add to application_controller.rb or your base controller:
before_filter :dev_reload if Rails.env.eql? 'development'
def dev_reload
# add lib files here
["rest_client.rb"].each do |lib_file|
ActiveSupport::Dependencies.load_file lib_file
end
end
Worked for me.

Resources