Rails same file name for different classes - ruby-on-rails

Having model Price (models/price.rb)
class Price
end
Also in lib directory I have import/detector/price.rb file
class Import::Detector::Price
end
Lib directory added to autoload paths via
config.autoload_paths += Dir["#{config.root}/lib/**/"]
So running Price.new I get error
Unable to autoload constant Price, expected lib/import/detector/price.rb to define it.
Import::Detector::Price.new is ok
What was my mistake?
UPD.
The most interesting
Also having this file models/car/property/price.rb
class Car::Property::Price
end
And everything ok with it. Car::Property::Price is available.

Try
config.autoload_paths += Dir["#{config.root}/lib"]
instead of
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Using **, Dir will return every directory under lib and will put them all (as root directories) in the load path. It should only be the main lib directory in the load path as rails will work out the subdirectories using the namespace.
Rails autoloading — how it works, and when it doesn't

Related

RoR autoload sub directories

I have created a "services" dir in app/ where I have created some classes (services). Now it's looks like this :
-app
-services
-class1
-class2
-class3
-class4
For now, I have added app/services in config/spring.rb
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
app/services
app/errors
).each { |path| Spring.watch(path) }
So my classes in services are loaded.
But now, I want to do this :
-app
-services
-dir1
-class1
-class2
-dir2
-class3
-class4
I got error :
uninitialized constant TransactionService::AuthorizeRequest
How autoload a dir and subdir ?
Rails tries to guess namespaces by dirnames & filenames. So, to have a TransactionService::AuthorizeRequest class name, you should have the exact following structure:
app
- services
-- transaction_service
--- authorize_request.rb
Your class sould looks like :
module TransactionService
class AuthorizeRequest
end
end

My libraries are not being loaded on production

Everything works fine locally.
In my application.rb :
module Maestra
class Application < Rails::Application
config.autoload_paths += Dir["#{config.root}/lib/MyLib/**/"]
Then I deploy, and in console MyLib is an undefined class.
So if I change my application.rb to :
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Then MyLib is a known class but it has no namespaces nor methods.
My directories are set up as so :
+ Lib
+ MyLib
MyLib.gemspec
+ lib
common.rb
my_custom_namespace.rb
So on my local I can very easily do : MyLib::MyCustomNamespace, but remotely, with the latter config in my application.rb, that namespace does not exist.

Rails - how to load the whole directory of files in /lib?

I have in the lib directory following structure:
/lib/dir_a/dir_b/dir_c/
In dir_c are stored images.
I am trying to load these images and display them in views. I have tried to set up the path to the images in views, but I got the 404 error.
So I did following: created a file in the initializers folder and into this file I put:
Dir[Rails.root + 'lib/dir_a'].each do |file|
require file
end
For loading all content stored in the dir_a directory (which involves as subdirectories as files).
But when I restarted server, I got this error:
...dependencies.rb:251:in `require': cannot load such file -- /Users/radek/rubydev/EDI/lib/brands (LoadError)
I also tried stuff like
Dir[Rails.root + 'lib/dir_a/'].each do |file|
or
Dir[Rails.root + 'lib/dir_a/**'].each do |file|
But none of those helped me.
Thus, is there any way to load a content from /lib directory and work with them in views?
Dir[Rails.root + 'lib/**/*.rb'].each do |file|
require file
end

How do I use config.assets.precompile for directories rather than single files?

How do I use config.assets.precompile in production to only include the files in 'lib/assets/javascripts', 'lib/assets/stylesheets', 'vendor/assets/javascripts' and 'vendor/assets/stylesheets'?
Basically something like:
config.assets.precompile += %w( pagespecific.js anotherpage.js )
But used to auto include files in specific directories that are not 'app/assets/javascripts' or 'app/assets/stylesheets'.
*edit: adding the solution I ended up using for page specific js
config.assets.precompile += ['pages/*.js']
You can simply write it like this:
config.assets.precompile += ['directory/*']
The point of compiling assets is to build one (or a small number of) files to minimize the number of HTTP requests from the browser.
If you're going to serve each file individually, then why not just disable precompile?
To use precompile as intended, build an entire directory into one file using Sprockets' require_directory:
//= require_directory ./awesome_js_app
...and list that file in your config.assets.precompile array.
By default, all CSS is built into application.css & JS into application.js. You can add more top-level files to compile with the precompile directive in config/environments/production.rb (and other envs if you wish.) For example:
config.assets.precompile += %w( public.css public.js )
Then the Sprockets //= require ... directives in those top-level files will determine the composition of final compiled file.
You can use these additional top-level files in your layouts to have different CSS & JS for certain views.
It's probably a bit better to include this as an asset path(as per your example solution it would be):
config.assets.paths << Rails.root.join('app', 'assets', 'javascripts', 'pages')
It also allows you to include paths not in the assets directory (for example with including the bootstrap-sass). These paths are then added to your assets folder in your public directory, and pushed to your asset location if using something like asset_sync.
I found this link, and think may be it helpful for you, please see
keithgaputis's answer. Rails config.assets.precompile setting to process all CSS and JS files in app/assets
I think you can do like following.
# In production.rb
config.assets.precompile << Proc.new { |path|
if path =~ /\.(css|js)\z/
full_path = Rails.application.assets.resolve(path).to_path
app_assets_path = Rails.root.join('app', 'assets').to_path
if full_path.starts_with? app_assets_path
puts "excluding asset: " + full_path
false
else
puts "including asset: " + full_path
true
end
else
false
end
}
As of Sprockets 3 you can use a manifest.js file to declare which files or directories are precompiled. See upgrade docs. So in your config you would add:
config.assets.precompile = %w(manifest.js)
Then in app/assets/config/manifest.js you can have
//= link_directory ../pages .js
Use link_tree if you want js files in nested sub-directories to be precompiled too.

Having a module and class with the same name

I have a module stat that exists in the directory structure: lib/stat_creator/stat/
In lib/stat_creator/stat.rb I have the files in the lib/stat_creator/stat/ directory that I require, as well as:
module StatCreator
module Stat
end
end
When I use that module I refer to the classes as
StatCreator::Stat::Foo.new
Now I want a root Stat class that lives in app. I've made my Stat class in app/models and set it up in routes.rb. But if I go to rails console and try to use the Stat class in app/models like:
Stat.by_user_id("ID")
I get the error: LoadError: Expected ../lib/stat_creator/stat.rb to define Stat
I thought the point of using namespaces was to avoid this kind of conflict, so I don't understand what I"m doing wrong.
I'd do:
::Stat.by_user_id("ID")

Resources