Rails Root directory path? - ruby-on-rails

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

Related

rails - files in autoload_paths folder aren't loaded

I have a app/extensions folder where my custom exceptions reside and where I extend some of the Ruby/Rails classes. Currently there are two files: exceptions.rb and float.rb.
The folder is specified in the ActiveSupport::Dependencies.autoload_paths:
/Users/mityakoval/rails/efo/app/extensions/**
/Users/mityakoval/rails/efo/app/assets
/Users/mityakoval/rails/efo/app/channels
/Users/mityakoval/rails/efo/app/controllers
/Users/mityakoval/rails/efo/app/controllers/concerns
/Users/mityakoval/rails/efo/app/extensions
/Users/mityakoval/rails/efo/app/helpers
/Users/mityakoval/rails/efo/app/jobs
/Users/mityakoval/rails/efo/app/mailers
/Users/mityakoval/rails/efo/app/models
/Users/mityakoval/rails/efo/app/models/concerns
/Users/mityakoval/rails/efo/app/template.xlsx
/Users/mityakoval/.rvm/gems/ruby-2.4.1#web_app/gems/font-awesome-rails-4.7.0.2/app/assets
/Users/mityakoval/.rvm/gems/ruby-2.4.1#web_app/gems/font-awesome-rails-4.7.0.2/app/helpers
/Users/mityakoval/rails/efo/test/mailers/previews
The reason for it to be listed there twice is that it should be automatically loaded since it was placed under app directory and I have also manually added it to the autoload_paths in application.rb:
config.autoload_paths << File.join(Rails.root, 'app', 'extensions/**')
The strange thing is that my exceptions.rb is successfully loaded at all times, but the float.rb isn't unless eager loading is enabled.
Answers to this question say that it might be related to Spring (which I tend to believe), so I've added the folder to spring.rb:
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
config/application.yml
app/extensions
).each { |path| Spring.watch(path) }
I've restarted Spring and the Rails server multiple times and nothing worked. Does anyone have any suggestions?
Ruby version: 2.4.1
Rails version: 5.1.5
EDIT
/Users/mityakoval/rails/efo/app/extensions/float.rb:
class Float
def comma_sep
self.to_s.gsub('.', ',')
end
end
rails console:
irb> num = 29.1
irb> num.comma_sep
NoMethodError: undefined method `comma_sep' for 29.1:Float
from (irb):2
A better way to monkeypatch a core class is by creating a module and including it in the class to be patched in an initializer:
# /lib/core_extensions/comma_seperated.rb
module CoreExtensions
module CommaSeperated
def comma_sep
self.to_s.gsub('.', ',')
end
end
end
# /app/initializers/core_extensions.rb
require Rails.root.join('lib', 'core_extensions', 'comma_seperated')
# or to require all files in dir:
Dir.glob(Rails.root.join('lib', 'core_extensions', '*.rb')).each do |f|
require f
end
Float.include CoreExtensions::CommaSeperated
Note that here we are not using the Rails autoloader at all and explicitly requiring the patch. Also note that we are placing the files in /lib not /app. Any files that are not application specific should be placed /lib.
Placing the monkey-patch in a module lets you test the code by including it in an arbitrary class.
class DummyFloat
include CoreExtensions::CommaSeperated
def initialize(value)
#value = value
end
def to_s
#value.to_s
end
end
RSpec.describe CoreExtensions::CommaSeperated do
subject { DummyFloat.new(1.01) }
it "produces a comma seperated string" do
expect(subject.comma_sep).to eq "1,01"
end
end
This also provides a much better stacktrace and makes it much easier to turn the monkey patch off and on.
But in this case I would argue that you don't need it in the first place - Rails has plenty of helpers to humanize and localize numbers in ActionView::Helpers::NumberHelper. NumberHelper also correctly provides helper methods instead of monkeypatching a core Ruby class which is generally best avoided.
See:
3 Ways to Monkey-Patch Without Making a Mess

Cannot override core ruby class in Rails 2.3.4

I want to extend the ruby class, for example,
# lib/core_ext/hash.rb
class Hash
def gop_compact
delete_if{|k, v| (k.blank? || v.blank?)}
end
end
I have created a separate folder in the /lib directory as follows,
lib/core_ext/hash.rb
And I tried to include this path in load_paths as follows,
# config/environment.rb
config.load_paths += %W( #{RAILS_ROOT}/lib/core_ext )
After all this setup, restarted the server and tried calling method on a Hash object but it throws an undefined method exception.
Note:- Rails version is 2.3.4
I spent lot of time on this but no luck yet. Any help is appreciated.
Thanks in advance!
Even though you've added the core_ext folder to your load paths, you'll still need to require it with require 'hash'. To minimize memory usage, Rails won't actually require ruby files just because you add them to your load_path.
>> Hash.instance_methods.grep(/gop/)
=> []
>> require "hash"
=> true
>> Hash.instance_methods.grep(/gop/)
=> [:gop_compact]

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.

Rails 3 autoload

I have a class ConstData:
class ConstData
US_CITIES = ['miami', 'new york']
EUROPERN_CITIES = ['madrid', 'london']
end
Its stored under /lib/const_data.rb
The idea is that inside a model, controller or view I can do:
ConstData::US_CITIES to get the US_CITIES etc
Rails should load this class automatically, I got this from:
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/662abfd1df9b2612?hl=en
However this does not work. Can anyone explain me how to accomplish this ?
The post #daniel refers to is from 2008. Rails has changed since then.
In fact, quite recently. Rails3 doesn't load the lib/ directory automatically.
You can reactivate it quite easily though. Open config/application.rb And add, in the config (in the Application class) the followin :
config.autoload_paths += %W(#{config.root}/lib)
Then your lib/ dir will be autoloaded.
The reason autoload_paths didn't work for you and you were forced to do:
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
is because you forgot to namespace your class.
lib/awesome/stuffs.rb should contain a class/module like this:
class/module Awesome::Stuffs
....
but you had:
class/module Stuffs
....
Rails can only autoload classes and modules whose name matches it's file path and file name.
:)
config.autoload_paths did not work for me. I solved it by putting the following in ApplicationController:
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
Follow the solution for lib dir be autoloaded:
Remove config.threadsafe! from development.rb and production.rb;
Add in config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
config.threadsafe!
config.dependency_loading = true

Why is my Rails.root nil?

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

Resources