How can I create globally-accessible modules in Rails? - ruby-on-rails

In Rails, I can create models which are global (accessible anywhere in the application). However, I'd like to create some constructs that are global, but don't correspond to any database table (which is why they can't be models) and won't ever be instantiated (so I need modules instead of classes).
I've tried using the initializers directory, which works, but is annoying because it requires restarting my server every time I change a value (whereas I can change the code in my models without restarting the server). What's the best way to create globally-accessible modules in this manner?

Just put it into lib sub-directory and add that to your config/application.rb:
config.autoload_paths += ["#{config.root}/lib"]

In addition to adding modules to the lib directory (which is appropriate), you can also put classes in the models directory. They don't have to be ActiveRecord based.

Related

Rails namespace service objects in app/services folder

I'm trying to put service objects into app/services folder but reference them via Services::SomeModel::SomeClass to better organize my code (the project is pretty large).
# app/services/tasks/create.rb
module Services
module Tasks
class Create
# ...
end
end
end
However, because of the way Rails loads the files, app/services is treated like a base folder and Rails keeps wanting the classes to be defined as ::Tasks::Create instead of ::Services::Tasks::Create.
I can solve this by placing my service objects in a subdirectory, like app/classes/services and then referencing them via ::Services::Tasks::Create, but I would prefer to have the /services folder in the /app directory itself.
I'm not a huge fan of the convention some use with services, naming them ::Tasks::CreateService. The whole reason I'm namespacing them the way I am is so anyone can look at the code and understand where the related files are located and to keep everything organized.
I've tried playing with auto_load in the config/application.rb file but that doesn't seem to work, since Rails is already pre-loading the files in app/* (that's my understanding).
Is there a way to reference service objects via ::Services::Model::Action and have the files located in app/services/model/action.rb?

Convention for naming PORO Models in Rails?

In an attempt to be more object-oriented, I find myself creating more POROs (Plain-old_ruby-objects). In rails, this simply means that the model class does not inherit from ActiveRecord::Base, and thus this model is not backed by a database table.
Lets say I have an app with hundreds of models. It would be nice if there was some naming convention of PORO models so that those PORO models can be quickly identified instead of having to open up each of their files and notice that they do not inherit from ActiveRecord::Base.
I could not find a naming convention for this. Does one exist in the rails community? If not, suggestions are welcome.
What I ended up doing was creating a subdirectory in my app/models directory called: poros.
In order to make those files within that poros subdirectory available within the load path, I had to go into config/application.rb and add this line:
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
Now I can access those POROs just like I can with any of the Models.
I'm not aware of any naming convention for poro classes in the Rails community, even though there has been a recent trend to keep classes inheriting from ActiveRecord::Base rather small.
If your classes are rather generic, they should be placed in the lib directory. If they are specific to your app but only require no interaction with other classes, you could create service classes placed in app/services. Similarly you can extract decorators, jobs and concerns.
Whatever classes remain can either stay in the appfolder, or be placed in a subdirectory.

Why do some "Plain Old Ruby Objects" go in app/models directory instead of lib direcory?

I am working on a project where the current developers have put their "Plain Old Ruby Objects" in the models directory of our Rails app.
I have seen most examples online where the PORO files go inside lib instead, but some say models.
Is there even a logical / specific reason why people put them in the models directory over the lib directory?
"Idiomatically" the models directory intended for code used to hold state. Most of the time this would be ActiveRecord subclasses corresponding to database tables. However frequently people put other stuff in the models directory. One thing often seen are code dropped here in order to take advantage of auto-reloading. (the lib dir doesn't normally auto-reload)
Based on the Getting Started Rails guide, the app/models/ directory is pretty much anything, whereas lib/ is for modules that are used across the entire app (e.g. extensions).
As #seand said, yes, one advantage is that the app/models/ directory automatically reloads, but I tend to think of it as any class that "interacts with other classes" should live in app/models/, with the only exception being a service class (which I tend to think of as "a class which manipulates the state of another class"), which I tend to put into app/services/.
I know a lot of developers would disagree with me - many I've talked to even create a separate directory namespaced to their app (e.g. if your app is named "MyBlog", they would create an app/myblog directory for any object not explicitly backed by the database, but not a module or a service class either.
That said, I think ultimately it boils down to a) personal preference and b) where you feel is best to place the PORO with respect to your app.
There is no hard and fast rule on where to put POROs. The rails community has been hashing this out for a while now. At one point the convention was to put stuff in the concerns directory but that seems to have fallen out of favor with some folks.
One rule of thumb for the difference between /lib and app/{blah} is that code in the /lib folder is code that you presumably can reuse across several projects e.g. general purpose class or utilities. for example if you have some custom monkey patches to core ruby or rails classes that you will use in multiple projects, a good place to but them would be in the lib folder. Anything in app/{blah} should pertain specifically to current project.
One way to think of lib folder is as the poor cousin of plugins and gems.
Just my 2 cents on the subject

Best way to extract code from controller

Using Pow and Rails 4 on OS X.
I have a SearchController which takes a query and searches for it on various backend services (YouTube, SoundCloud, Last.fm, etc).
I want to take these backends and put inside their own files/classes, to keep the code clean and make it easy to add more backends.
So my question is: where should I put these files? I have tried to make a folder called backend, containing all files, and put it inside app/controller and app/models. I then put require 'backend/lastfm.rb' in my controller and it works. But it's only loaded once, so I have to touch tmp/restart.txt every time I make a change. Not ideal!
Same issue when putting it into lib, even when I try to use eager loading.
So where can I put this folder so I can use the code from my SearchController and have it reload the files at every request (in development mode)?
Thanks!
For autoload your folders you should add paths to application.rb:
class Application < Rails::Application
config.autoload_paths += %W(#{config.root}/app/backend/*)
end
Now you backend folder autoload, and you do not need requires you files.

Why should I add things to the /lib directory over /config/initializers?

Functionally speaking, it seems like adding a new file to these locations has the same effect except files added to /config/initializers are automatically required. Given this advantage, is there any reason to add files to /lib?
Are there any other differences between these two folders?
config/initializes/ is for things you want loaded when you app loads hence 'initializer'.
As for lib/ you want to add your tasks such as rake files, cron jobs, etc.
You can think of it like this: initializes are self contained and don't get called where as the library contains things that get called.

Resources