I'm trying to reference Rails.root in my application.rb but it is nil, why is that?
I can explain why, but I can't give you a workaround.
Rails.root is defined in rails/railties/lib/rails.rb
def root
application && application.config.root
end
In application.rb, the instance of application is not yet created, because the Application class is being defined... The application is only initialized after, in environment.rb:
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
Testapp::Application.initialize!
EDIT
The workaround is right before our eyes:
my_rails_root = File.expand_path('../..', __FILE__)
Are you using Rails 3.x? If not, you should be using RAILS_ROOT rather than Rails.root.
I had the same issue when I tried to use it before the module and class declaration. Try using it inside and see if that makes a difference e.g.
module MyApp
class Application < Rails::Application
puts Rails.root
end
end
Related
I have some code i've inherited and am in the process of upgrading it to Rails 3.1. I'm suuuuper close to done but I got a bug.
In Rails Console I run User.first and I get this error
undefined local variable or method `acts_as_userstamp' for #<Class:0x000000046bef50>
Now acts_as_userstamp is a method located on line two inside my User model
class User < ActiveRecord::Base
#TODO /lib is not loading??? or is it??? why this method not work in browser?
acts_as_userstamp
And is defined in a file called app/lib/model_modifications.rb.
Now I recently discovered that my app/lib folder was not being autoloaded in my application.rb file and I think that's been fixed...or has it? Is this file correct? Or no?
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# evil outdated soap middleware, TODO: kill it with fire
# Does this have to be loaded BEFORE the first line???
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "soap4r"))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "plugins", "soap4r-middleware", "lib"))
# evil outdated soap middleware, TODO: kill it with fire
require 'soap4r-middleware'
require File.join(File.dirname(__FILE__), '..', 'app', 'lib', 'soap.rb')
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 MyappDev
class Application < Rails::Application
# startup the lib directory goodies <-- IS THIS CORRECT???
# config.autoload_paths << "#{Rails.root}/lib"
# config.autoload_paths += %W( lib/ )
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
# 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]
config.middleware.use MyAPIMiddleware
end
end
I'm trying to debug this file as I post this now. Here is a peak at it's internal structure...(i've just included the overall structure for the sake of brevity)
app/lib/model_modificatons.rb
class Bignum
...
end
class Fixnum
...
end
class ProcessorDaemon
...
end
module ActiveRecord
module UserMonitor
...
end
module MyLogger
...
end
end
class Object
...
end
class Struct
...
end
class String
...
end
class Fixnum
...
end
class OpenStruct
...
end
class ActiveRecord::Base
def self.visible_columns
...
end
...
def self.acts_as_userstamp
logger.info "HI fonso - acts_as_userstamp is called"
include ActiveRecord::UserMonitor
end
...
protected
def self.range_math(*ranges)
...
end
end
class Array
...
end
class DB
...
end
If you can spot a problem with the overall structure or anywhere else please let me know.
So why is this method not found? I'm trying to debug it as I'm posting this and I'm getting nothing.
I suspect the file app/lib/model_modifications.rb is not being loading. That nothing in the /lib directory is being loaded..but how do I confirm this?
Thank you for reading this far, I hope I've not rambled on too much.
autoload_path configuration does not load all the given files on the boot but defines folders where rails will be searching for defined constants.
When your application is loaded, most of the constants in your application are not there. Rails have a "clever" way of delaying loading the files by using a constant_missing method on Module. Basically, when Ruby encounters a constant in the code and fails to resolve it, it executes said method. THe sntandard implementation of this method is to raise UndefinedConstant exception, but rails overrides it to search all of its autoload_paths for a file with a name matching the missing constant, require it and then check again if the missing constant is now present.
So, in your code everything works as expected and you need to load this extension file manually. If you want to have some code that executes on the application boot, put your file within config/initializers folder.
Aside: Try avoiding monkey patching whenever possible. It might be looking clever, but adding more methods to already overpopulated classes will not make them easier to use.
After upgrading to Rails 5.2, (edit: using "5.2.0.rc1") I now have ?locale=en being added to my urls when I use a path constructed from path_helper (like login_path). How do I stop Rails from adding the locale to my urls? I don't need them, ever.
My controller:
```
#home_controller.rb
def index
redirect_to login_path
end
```
Application.rb
```
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module MyApp
class Application < Rails::Application
config.assets.initialize_on_precompile = false
config.generators do |g|
g.fixture_replacement :rspec
g.fixture_replacement :factory_bot
end
end
end
```
What Happens:
It redirects me to localhost:3000/login?locale=en
It seems like somewhere along the line in Rails 5 the path_helper regressed to no longer omit optional params like locale when constructing URLs. Only thing to do is wait for a PR to fix it. Looks like a lot have been made but unclear if they have been merged or if the fix exists in 5.2.1
https://github.com/rails/rails/pull/32526
https://github.com/rails/rails/pull/32382
https://github.com/rails/rails/pull/33846
I am trying to learn Middlewares and been practising how to mount it in the Rails application. I have followed the railscast
So far I have implemented these steps:
1) Created a new Rails 4.2 application called: Blog
2) Added a file in the lib folder named as response_timer.rb.
class ResponseTimer
def initialize(app)
#app = app
end
def call(env)
[200, {"Content-Type" => "text/html"}, "Hello World"]
end
end
3) Added config.middleware.use "ResponseTimer" in application.rb.
config.middleware.use "ResponseTimer"
But as i'm hitting the command rake middleware in the terminal, it is reporting this error:
rake aborted!
NameError: uninitialized constant ResponseTimer
I tried also to add the config.middleware.use "ResponseTimer" in the development.rb but again facing the same error.
What am i missing here?
Please help.
Referenced article: http://guides.rubyonrails.org/rails_on_rack.html
Middleware has to have an accompanying module / class, and needs to be loaded in the app before it can be referenced. The way to do this in Rails is with autoloading (lib files aren't autoloaded by default):
#config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.middleware.use "ResponseTimer"
The above should work for you.
I followed this answer: https://stackoverflow.com/a/24122424
I tried it before but maybe missed something before.
In appliation.rb
require 'rails/all'
require_relative '../lib/response_timer'
module Blog
class Application < Rails::Application
...
config.middleware.use ResponseTimer
end
end
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.
How do I get my Rails app's root directory path?
In Rails 3 and newer:
Rails.root
which returns a Pathname object. If you want a string you have to add .to_s. If you want another path in your Rails app, you can use join like this:
Rails.root.join('app', 'assets', 'images', 'logo.png')
In Rails 2 you can use the RAILS_ROOT constant, which is a string.
For super correctness, you should use:
Rails.root.join('foo','bar')
which will allow your app to work on platforms where / is not the directory separator, should anyone try and run it on one.
You can access rails app path using variable RAILS_ROOT.
For example:
render :file => "#{RAILS_ROOT}/public/layouts/mylayout.html.erb"
In addition to all the other correct answers, since Rails.root is a Pathname object, this won't work:
Rails.root + '/app/assets/...'
You could use something like join
Rails.root.join('app', 'assets')
If you want a string use this:
Rails.root.join('app', 'assets').to_s
In some cases you may want the Rails root without having to load Rails.
For example, you get a quicker feedback cycle when TDD'ing models that do not depend on Rails by requiring spec_helper instead of rails_helper.
# spec/spec_helper.rb
require 'pathname'
rails_root = Pathname.new('..').expand_path(File.dirname(__FILE__))
[
rails_root.join('app', 'models'),
# Add your decorators, services, etc.
].each do |path|
$LOAD_PATH.unshift path.to_s
end
Which allows you to easily load Plain Old Ruby Objects from their spec files.
# spec/models/poro_spec.rb
require 'spec_helper'
require 'poro'
RSpec.describe ...
module Rails
def self.root
File.expand_path("..", __dir__)
end
end
source:
https://github.com/rails/rails/blob/5259062868dcf10fbcf735d6520e6a14e15fdcdb/actionmailer/test/abstract_unit.rb#L12
You can use:
Rails.root
But to to join the assets you can use:
Rails.root.join(*%w( app assets))
Hopefully this helps you.
Simply by Rails.root or if you want append something we can use it like Rails.root.join('app', 'assets').to_s
Simply By writing Rails.root
and append anything by
Rails.root.join(*%w( app assets)).to_s