When to consider creating your own Ruby module in a Rails app? - ruby-on-rails

With a Ruby module, you can cluster together a bunch of methods that you might use in one place and then include them into a class so it's as if you had written them in that class.
What kinds of practical uses are there for Ruby modules in a rails app?
I would appreciate if someone could mention an example of where they've actually used a module of their own so I have a sense of what situations I should be thinking about creating them. Thanks.

1) Any time I'm about to duplicate (or substantially duplicate) a piece of code: "oh, i could just cut/paste into this other controller . . . "
2) Any time I write code that is very obviously going to be reused in the future.
3) Code of substantial size that has a specific purpose, where that purpose is fairly distinct from the main purpose of the controller/model. This is somewhat related to (2), but sometimes code won't get reused but a module helps for organization.

You can place them in the /lib directory and they'll be loaded with your Rails project.
For example, you can view this repo of mine of an old project: lib directory of a Rails project
So for example, I have the following module:
google_charts.rb
Module GCharts
class GoogleCharts
def some_method
end
end
end
And anywhere in my Rails app, I can access the methods.
So if I were to access it from a controller, I would simply do:
require 'google_charts'
GCharts::GoogleCharts.some_method

We use modules for functionality that isn't tied to ActiveRecord models and hasn't been abstracted into a plugin or gem.
A recent example from our production code base is a library for integrating with Campaign Monitor for email list management. The core of the system uses our user model, but the actual interaction with the extenrl service is abstracted through a module that lives in /lib.

Related

Extend Rails within Engine

I did a Rails extension as suggested by
extending rails question using Harish Shetty answer.
I like it so much I decided to use it in my Rails Engine. Didn't quite work.
To make it work i place the file active_record_extensions in the Lib/[ENGINE] directory and added the Require active_record_extension to my engine.rb file.
This works, but I wonder if there's is a more proper way to do it.
Also. I ran into an Issue, (don't know if i'm allowed to piggyback a second question).
I have a Model called Translation. When i use the extended class method with that model i invoke an error 'Circular dependency detected' with
raise "Circular dependency detected while autoloading constant #{qualified_name}"
I'm guessing that using the model extension exposed the name to something that doesn't like the fact that I used Translation. (doesn't happen with the other models I have). I get around it by not using the extend class method with that model.

Can I have common namespaces in new rails applications?

Is it possible to create whole rails applications under a common namespace?
Lets assume that my company name is Acme, Inc. and I have the following rails projects: Blog, Store, WebService.
By default, if I do something like rails new blog the generated applications will be like:
module Blog
class Application < Rails::Application
module Store
class Application < Rails::Application
module WebService
class Application < Rails::Application
where every project/application is self contained and there is no implicit reference to the company. Ideally I would like to have all this applications under the company namespace, so we can refer to them as:
AcmeInc::Blog::Application
AcmeInc::Blog::Entities::Article
AcmeInc::Store::Application
AcmeInc::Store::Entities::Product
AcmeInc::Store::Entities::Order
AcmeInc::Store::Entities::Customer
etc...
Is this possible? Recommended?
Using:
ruby-2.0.0-p451, rails 3.2.17
Update
Snapshot of generated files and project structure after doing rails new acme/blog as suggested:
The correct way to do this is with engines. Each engine is like a standalone app, with it's own routes, test suite, etc, but you can have some common infrastructure like rake tasks, etc.
http://guides.rubyonrails.org/engines.html
I think I am probably late here to answer this, as others have already suggested nice approaches. Like, maintaining code within one common repository and creating rails engine.
I would like to share this famous project called spree, which follows the architecture you're looking for. You can visit spree's code on github here.
For example:
Spree::Core - spree_core engine as a gem to maintain all models and base modules etc.
Spree::Backend - spree_backend engine as a gem to maintain all admin related controllers, views, assets etc.
Spree::Frontend - spree_frontend engine as a gem to maintain user facing code i.e. controllers, views, assets related to it.
I guess you can use it as a reference for your application development.
If your trying to manage your code, why don't you just make a Blog Gem that you can include in each application. Then you would manage the code under one common repository for the Gem. Sees to me that's the Rails/Ruby way to do this

Can multiple Rails Applications share models/common business domain data between them?

I have several use cases that manipulate and add to the same data at different points in the process.
Each of these use cases share many of the same models, and actions in the process but would require totally different views and structure.
I was thinking of trying out the tips in this article from 8thLight but this was written in 2007.
http://blog.8thlight.com/jim-suchy/2007/02/20/sharing-a-database-among-multiple-rails-applications.html
According to them, the trick is to
(1) make a new folder with the shared models right above the application.
applications_in_same_business_domain
|-shared_models
|-application1
|-application2
|-...
(2) require this new folder or module in your application via enviorments.rb file
(which I believe the equivalent would be config/application.rb because I don't see enviornments.rb in Rails 3.)
They say some code like this will work (in environments.rb)
$: << File.dirname(__FILE__) + '/your_lib_path'
I tried this and it isn't working (in application.rb)...
config.autoload_paths += %W(../../../mardom_shared_models)
Is this the standard way to do this?
An API sounds like another way to do this...but...I don't know anything about API's here. Self-learning 6-Month Noob here)
Helping me get the above to work if it is possible I guess would be the specific question. Can I do this?
But any comments or articles on other matter would be appreciated.
I would need to modify the Rails generators here starting from this link: http://guides.rubyonrails.org/generators.html
I would rather put all models related stuff into a gem, and install gem locally to vengor/gems directory to simplify navigating in it.

Rails: Where to place plugin files

I am relatively new to Rails and recently found a couple of useful gems like authlogic that will help in getting the project up and about really fast. However, I have been wondering where to place the model, view, and controller files that are dependent on the plugin, but are core concepts of my project.
For example, is it better to place the User, Role, Session, etc.. models and related controllers with the plugin inside the vendor/ directory, or should I place them inside the root model/, view/, and controllers/ directories respectively?
Even models/views/controllers dependent on plugins should be kept in the app/model, app/view, and app/controllers directories along with your other code.
The "structural" reason is that the bulk of all those files will still be specific to your application. You will probably end up adding fields to the user, or adding has_many statements to your User model, etc. You want all that code with the rest of your core application code in the app directory.
The "functional" reason is that vender/plugins is only for the code specifically relating to that plugin and is treated differently during development. For instance, when you add a new plugin, it is not auto-loaded in development mode. So if your core files were there, they would not be auto reloaded even in development mode.
Anything you write should be in the standard directories. Use vendor for vendor-provided code.
Just as a heads up it is very hard to go wrong watching railscasts on topics you are new to.
Ryan Bates has two covering authlogic and authlogic with OpenID and in anticipation of your next step after authentication- authorization: He has some covering access control as well: Declarative Authorization, and CanCan.

How are require, require_dependency and constants reloading related in Rails?

How are require and require_dependency different?
How can require_dependency automatically reload classes in development but require can't ?
I digged into Rails' ActiveSupport::Dependencies and dispatcher.rb code. What I saw in require_dependency's code is it basically adds the constants to an autoloaded_constants array. But it gets cleared in clear_application inside dispatcher after each request.
Can someone give a clear explanation or point me to some resources which will help?
require (and its cousin load) are core Ruby methods. require_dependency is a method that helps Rails handle the problem of dependency management. Long story short, it allows Rails to reload classes in development mode so that you don't have to restart the server each time you make a code change. The Rails framework will require_dependency your code so that it can track and reload it when changes are made. The standard Ruby require doesn't do that. As an app (or plugin/engine) developer you should not have to worry about require_dependency as this is purely internal to Rails.
The magic of the Rails class loading process is in the ActiveSupport::Dependencies module. This code extends the default Ruby behavior to allow code inside your Rails app to automatically load modules (including classes which inherit from Module) using Rails' path and file naming conventions. This eliminates the need for the programmer to litter their code with require calls like you would in a plain Ruby application.
To put it another way, this lets you define class Admin::User inside the file app/models/admin/user.rb and have Rails know what you are talking about when you call Admin::User.new from another part of the application like a controller. Without ActiveSupport::Dependencies involved you would have to manually require everything you needed.
If you are coming from a statically typed language like C#, Java, etc then this might be a surprise: Rails code is not loaded until it is needed. For example, a User model class isn't defined and user.rb isn't loaded until AFTER you try to call User.whatever_method_here. Rails prevents Ruby from complaining about that missing constant, loads code for User, and then allows Ruby to continue as normal.
While I can't speak for your specific need, I would be very surprised if you actually needed to use the require_dependency method from within a plugin or engine. If you follow Rails conventions you shouldn't have to tweak the $LOAD_PATH by hand, either. This is not "the Rails way".
In the world of Ruby and also Rails simplicity and clarity is key. If all you want to do is write a plugin or engine and you are already diving deep into internals then you may consider approaching your problem from a different angle. My gut tells me that you may be trying to do something that is needlessly complicated. But then again, I have no clue what you are doing exactly!! :)
require_dependency is useful in an engine when you want to re-open a class which is not defined in your engine (for example in another engine or Rails app) and have it reloaded. In which case something like this works:
# app/controllers/my_engine/documents_controller.rb
require_dependency MyEngine::Engine.root.join('app', 'controllers', 'my_engine', 'documents_controller').to_s
module MyEngine
class DocumentsController
def show
render :text => 'different'
end
end
end

Resources