We are creating several applications (new development) at our company. To try and establish a common look and feel between these apps I would like to create a gem that:
Incorporates specific versions of gems like bootstrap-sass
Declares several common CSS styles, using mixins from bootstrap where appropriate
Provides other assets as well.
I want the applications that we develop to merely have to include my common-ui gem, they should not include things like bootstrap directly.
The pattern for exposing scss from a gem is pretty straight forward (just take a look at the bootstrap-sass project); where things get interesting is when my scss needs to access bootstrap. When an application includes my scss, the pipeline complains that it cannot locate bootstrap and everything comes to a halt.
What is the best approach to creating a gem that does what I have described?
============================================================================
To better follow SO's format, I am going to answer my question with what I came up with (and why I think it works). I am somewhat new to rails, so my answer is by no means authoritative. Feel free to comment or propose a better way of doing things.
============================================================================
See caveat in the question, this may be a spectacularly bad way to solve this problem
Here's what's working so far. For a gem to expose assets to an application's asset pipeline, it must be initialized as an engine. The problem with one gem using another's assets is that the other gem's engine may not have been initialized and therefore the pipeline doesn't know about the other gems assets.
To work around this, just require the root file from the other gem in your root file. So in lib/company-common-ui.rb, I have the following:
require "company-common-ui/version"
module Company
module Common
module Ui
# We don't really need anything here
end
end
end
require "company-common-ui/engine"
require "bootstrap-sass"
I feel like I understand the difference between require and require_dependency (from How are require, require_dependency and constants reloading related in Rails?).
However, I'm wondering what should happen if I use some of the various methods out there (see http://hemju.com/2010/09/22/rails-3-quicktip-autoload-lib-directory-including-all-subdirectories/ and Best way to load module/class from lib folder in Rails 3?) to get all files loading so we:
don't need to use require_dependency all over the place in the application and
don't have to restart development servers when files in the lib directory change.
It seems like development performance would be slightly impacted, which is not that big of a deal to me. How would performance be impacted in a production environment? Do all of the files generally get loaded only once if you are in production anyway? Is there a better way that I'm not seeing?
If you could include some resources where I could read more about this, they would be greatly appreciated. Some blog posts said that this behavior changed recently with Rails 3 for autoreloading lib/* files and that it was contentious, but I didn't see any links to these discussions. It would be helpful for considering the pros/cons. Thanks!
The code reloader is disabled by default in production. So if you are calling require_dependency at the top of a file it is going to be executed only once.
The Rails 3 change you mentioned is really small. You can usually call Foo and it will be loaded from app/models/foo.rb automatically. Before it could also be loaded from lib/foo.rb. (These directories app/models and lib are called autoload paths.) Rails team decided to remove lib from autoload paths in the 3rd version. You can still put it back. But it is encouraged to leave in lib less frequenttly-changed and project-specific files. If you have something that does not belong to any of the default app subdirectories like app/models or app/controllers you don't have to put it in lib. You can add your own subdirectory. I have app/presenters, for example. There is a discussion on the old issue tracker if you want more info on that.
I want to add a library that I wrote to a Rails app (and to other Rails apps later). I tried putting it in /lib which seemed logical...
[RAILS_ROOT]/lib/my_lib/the_main_file.rb
[RAILS_ROOT]/lib/my_lib/some_other_file.rb
Then...
require 'my_lib/the_main_file'
That works fine.
But is that a great way to do it?
Now I have to put that require everywhere I want to call the library.
I thought about putting the require in an initializer but that seems kind of weird.
What do people usually do about this?
Using an initializer may look weird when you have a single file to include, but sometimes I have many files that I want to add, and end up using an intializer that only includes stuff. It's actually pretty neat.
I'm not sure about the "best practices"(tm) or anything, but we do a similar thing for our project as well. The library is in lib, and the require in an initializer (app_config.rb in our case). This seems like a good way to do things, and hasn't bitten us in the butt thus far :) Hope that helps.
I usually wrap up my stuff in classes. If you add config.autoload_paths += %W(#{config.root}/lib) to your application.rb then any reference to a missing constant will result in an attempt to autoload it, i.e just using MyClass.new will make it try to load `lib/my_class.rb'.
Have a look at Best way to load module/class from lib folder in Rails 3?
Since the latest Rails 3 release is not auto-loading modules and classes from lib anymore,
what would be the best way to load them?
From github:
A few changes were done in this commit:
Do not autoload code in *lib* for applications (now you need to explicitly
require them). This makes an application behave closer to an engine
(code in lib is still autoloaded for plugins);
As of Rails 2.3.9, there is a setting in config/application.rb in which you can specify directories that contain files you want autoloaded.
From application.rb:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Source: Rails 3 Quicktip: Autoload lib directory including all subdirectories, avoid lazy loading
Please mind that files contained in the lib folder are only loaded when the server is started. If you want the comfort to autoreload those files, read: Rails 3 Quicktip: Auto reload lib folders in development mode. Be aware that this is not meant for a production environment since the permanent reload slows down the machine.
The magic of autoloading stuff
I think the option controlling the folders from which autoloading stuff gets done has been sufficiently covered in other answers. However, in case someone else is having trouble stuff loaded though they've had their autoload paths modified as required, then this answer tries to explain what is the magic behind this autoload thing.
So when it comes to loading stuff from subdirectories there's a gotcha or a convention you should be aware. Sometimes the Ruby/Rails magic (this time mostly Rails) can make it difficult to understand why something is happening. Any module declared in the autoload paths will only be loaded if the module name corresponds to the parent directory name. So in case you try to put into lib/my_stuff/bar.rb something like:
module Foo
class Bar
end
end
It will not be loaded automagically. Then again if you rename the parent dir to foo thus hosting your module at path: lib/foo/bar.rb. It will be there for you. Another option is to name the file you want autoloaded by the module name. Obviously there can only be one file by that name then. In case you need to split your stuff into many files you could of course use that one file to require other files, but I don't recommend that, because then when on development mode and you modify those other files then Rails is unable to automagically reload them for you. But if you really want you could have one file by the module name that then specifies the actual files required to use the module. So you could have two files: lib/my_stuff/bar.rb and lib/my_stuff/foo.rb and the former being the same as above and the latter containing a single line: require "bar" and that would work just the same.
P.S. I feel compelled to add one more important thing. As of lately, whenever I want to have something in the lib directory that needs to get autoloaded, I tend to start thinking that if this is something that I'm actually developing specifically for this project (which it usually is, it might some day turn into a "static" snippet of code used in many projects or a git submodule, etc.. in which case it definitely should be in the lib folder) then perhaps its place is not in the lib folder at all. Perhaps it should be in a subfolder under the app folderĀ· I have a feeling that this is the new rails way of doing things. Obviously, the same magic is in work wherever in you autoload paths you put your stuff in so it's good to these things. Anyway, this is just my thoughts on the subject. You are free to disagree. :)
UPDATE: About the type of magic..
As severin pointed out in his comment, the core "autoload a module mechanism" sure is part of Ruby, but the autoload paths stuff isn't. You don't need Rails to do autoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). And when you would try to reference the module Foo for the first time then it would be loaded for you. However what Rails does is it gives us a way to try and load stuff automagically from registered folders and this has been implemented in such a way that it needs to assume something about the naming conventions. If it had not been implemented like that, then every time you reference something that's not currently loaded it would have to go through all of the files in all of the autoload folders and check if any of them contains what you were trying to reference. This in turn would defeat the idea of autoloading and autoreloading. However, with these conventions in place it can deduct from the module/class your trying to load where that might be defined and just load that.
Warning: if you want to load the 'monkey patch' or 'open class' from your 'lib' folder, don't use the 'autoload' approach!!!
"config.autoload_paths" approach: only works if you are loading a class that defined only in ONE place. If some class has been already defined somewhere else, then you can't load it again by this approach.
"config/initializer/load_rb_file.rb" approach: always works! whatever the target class is a new class or an "open class" or "monkey patch" for existing class, it always works!
For more details , see: https://stackoverflow.com/a/6797707/445908
Very similar, but I think this is a little more elegant:
config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
In my case I was trying to simply load a file directly under the lib dir.
Within application.rb...
require '/lib/this_file.rb'
wasn't working, even in console and then when I tried
require './lib/this_file.rb'
and rails loads the file perfectly.
I'm still pretty noob and I'm not sure why this works but it works. If someone would like to explain it to me I'd appreciate it :D I hope this helps someone either way.
I had the same problem. Here is how I solved it. The solution loads the lib directory and all the subdirectories (not only the direct). Of course you can use this for all directories.
# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
As of Rails 5, it is recommended to put the lib folder under app directory or instead create other meaningful name spaces for the folder as services , presenters, features etc and put it under app directory for auto loading by rails.
Please check this GitHub Discussion Link as well.
config.autoload_paths does not work for me. I solve it in other way
Ruby on rails 3 do not automatic reload (autoload) code from /lib folder. I solve it by putting inside ApplicationController
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
If only certain files need access to the modules in lib, just add a require statement to the files that need it. For example, if one model needs to access one module, add:
require 'mymodule'
at the top of the model.rb file.
Spell the filename correctly.
Seriously. I battled with a class for an hour because the class was Governance::ArchitectureBoard and the file was in lib/governance/architecture_baord.rb (transposed O and A in "board")
Seems obvious in retrospect, but it was the devil tracking that down. If the class is not defined in the file that Rails expects it to be in based on munging the class name, it is simply not going to find it.
There are several reasons you could have problems loading from lib - see here for details - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/
fix autoload path
threadsafe related
naming relating
...
I'm attempting to reopen the String class in rails and add a bunch more methods for my app to use. Writing the code isn't a problem - my question is rather about where this code should go.
It doesn't make sense to me to reopen a class inside a different model file, because it really has nothing to do with any of the models specifically. I thought perhaps somewhere in config or lib would make sense, but I'm not particularly well versed with RoR yet.
To summarize, where would be the most logical place to define class-modifying code, and are there any implications depending on where/when the code is loaded?
The most logical place is probably in a file in the config/initializers directory. Any *.rb file you put in here will be automatically executed when rails boots. If you want, you could put them in a sub folder, so you could do something like config/initializers/extensions/*.rb.
I try keep these monkey-patches to a minimum, only when they are very clearly in the best interest of my code.
Lately I have preferred to keep the files organized in folders such as lib/monkey/string.rb, lib/monkey/hash.rb, etc. I then require all files in the lib/monkey folder in my environment.rb file.
# Load all monkey-patches.
Dir["lib/monkey/*.rb"].each {|monkeyfile| require monkeyfile}
This keeps all of my class modifying code isolated to one location, should a problem arise. I also enjoy the somewhat goofy naming, because it makes it stand out as something to be mindful of. Someone may have a better system, if so ... I'd love to hear about it!