Breaking a Large Rails App into Smaller Apps

Breaking a large rails app into smaller apps?

Dude, thats a pretty insane amount of models... anyways for handling complex logic and easily reuse them across other projects I would recommend to you the engines (from 2.3+ is part of Rails).

With that in place you can split your model in different modules (engines)

http://railscasts.com/episodes/149-rails-engines

Toño

What to do when a rails application become too big?

There are some great suggestions here about to to split up a Rails code base however I think that before you apply any of then you need to stop and seriously consider how you got into this position. All of these solutions introduce new complexities and challenges. They might be worthwhile trade offs but only if you make sure they also solve a problem you have today.

Take each of the pain points you listed (startup time is slow, memory use if high, performance is poor, rest performance is poor, development speed is slow) and run a "5 whys" exercise on them. Why are these things happening. Why did the app get into this state.

Most importantly before you commit to any plan for splitting up a large app consider if the app should be large in the first place. If your app is more complex than your product demands then switching to an equally complex cluster of services is not an improvement.

More concretely I would recommend against shared database access between apps/services/whatever. A shared database has a shared schema which becomes fragile. It also leads to tightly coupled services which lack the separation of concerns you need to see any improvement in your pace of development. Just as splitting one massive class into several tightly coupled files does not improve it nor does splitting one app into coupled services.
If you must maintain a large app you need to isolate separate concerns. In order to do so you need to break the dependencies between them. Based on the efforts I have seen to repair Rails monoliths you'll have better success creating clean interface within your existing app an then splitting out components than if you split the app apart and then hope the resulting pieces can be improved independently.

Ruby: How to properly split an app into multiple gems

Gems don't need the Gemfile.lock file, since their dependencies are declared in the gemspec.

To add a dependency use add_runtime_dependency:

spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4'

But this is not specific enough for deployment scenarios!
Well, true, but for a gem deployment means it is deployed into an application. The application should have the Gemfile.lock file to pin down the specific library versions.

An application deployment needs to be fully replicable, so build numbers of all library versions should be meticulously maintained. Gems, on the other hand, strive to be compatible to as many versions as possible to be re-usable, otherwise, one gem update will break all the gems which depend on it.

As for the rest of your question (whether and how to split your app into gems) - I believe this is not the right forum for that, as it is too broad for SO, but I wish you luck on your endeavor for making your software more manageable and more re-usable!

How to split routes.rb into smaller files

You can do that:

routes.rb

require 'application_routes'
require 'rest_api_routes'

lib/application_routes.rb

YourApplication::Application.routes.draw do
# Application related routes
end

lib/rest_api_routes.rb

YourApplication::Application.routes.draw do
# REST API related routes
end

UPDATE: (This method has since been removed from Rails)

Rails edge just got a great addition, multiple route files:

# config/routes.rb
draw :admin

# config/routes/admin.rb
namespace :admin do
resources :posts
end

This will come handy for breaking down complex route files in large apps.

Integrating multiple apps in Rails

You might consider breaking your apps into engines. It's a great way to isolate functionality and make code modular. Here's a link to the Rails engine docs: http://guides.rubyonrails.org/engines.html

If you need examples of real-world uses of engines you might consider looking at the code for Spree: https://github.com/spree/spree

With Spree you can add custom functionality by installing or building extensions, which are effectively Rails engines.

If you want to reference local gems/engines, you can point to them in your Gemfile like this:

gem 'mygem', :path => '/path/to/gem'

But make sure that the individual gems within your project don't have a .git folder, or you might run into errors regarding sub-modules.

Is it the Rails Way to build a single giant application, or modularize?

The convention is generally:

  • Build as one application
  • Have the classes know as little as possible about other classes
  • Extract when it hurts

Extracting to either engines or to services (service-oriented-architecture) is a decision for your scalability requirements.

How to organize controller in moderately large Rails application?

For organizing within our applications, I have done a little bit of everything depending on the situation.

First, regarding the separate controllers for admin/user functions, I will say that you probably don't want to go that route. We used authorization and before_filter to manage rights within the application. We rolled our own, but 20/20 hind-sight, we should have use CanCan. From there you can setup something like this (this is pseudo-code, actual language would depend on how you implemented authorization):

before_filter :can_edit_user, :only => [:new, :create, :edit, :update] #or :except => [:index, :show]

protected

def can_edit_user
redirect_to never_never_land_path unless current_user.has_rights?('edit_user')
end

Or at a higher level

before_filter :require_admin, :only [:new, :create]

and in your application controller

def require_admin
redirect_to never_never_land_path unless current_user.administrator?
end

It would depend which route, but I would use that for authorization instead of splitting up controllers.

As far as name spaces vs. Nested Resources, it depends on the situation. In several of our apps, we have both. We use name spaces when there is a cause for a logical separation or there will be shared functions between a group of controllers. Case and point for us is we put administrative functions within a namespace, and within we have users, roles and other proprietary admin functions.

map.namespace :admin do |admin|
admin.resources :users
admin.resources :roles
end

and then within those controllers we have a base controller, that stores our shared functions.

class Admin::Base < ApplicationController
before_filter :require_admin
end

class Admin::UsersController < Admin::Base
def new
....
end

This provides us logical separation of data and the ability to dry up our code a bit by sharing things like the before_filter.

We use nested controllers if there is going to be a section of code where you want some things to persist between controllers. The case from our application is our customers. We search for and load a customer and then within that customer, they have orders, tickets, locations. Within that area we have the customer loaded while we look at the different tabs.

map.resources :customers do |customer|
customer.resources :tickets
customer.resources :orders
customer.resources :locations
end

and that gives us urls:

customers/:id
customers/:customer_id/orders/:id
customers/:customer_id/tickets/:id

Other advantages we have experienced from this is ease of setting up menu systems and tabs. These structures lend themselves well to an organized site.

I hope this helps!

Advice/tools for working on a large existing rails application?

Railroad should help you understand the big picture. It generates diagrams for your models and controllers.



Related Topics



Leave a reply



Submit