Back to Home

How to implement HMVC pattern in Rails

Rails engins? Not! This is a great way to create “embedded” applications. But if you want to make a request in another engine · this will block another instance of your server. Therefore · if ...

How to implement HMVC pattern in Rails

Original author: r_wilco
  • Transfer



Rails engins? Not!


This is a great way to create “embedded” applications. But if you want to make a request in another engine, this will block another instance of your server. Therefore, if you have a high-level HMVC structure, then you will need to have many running instances of the application in order to ensure the operation of the application.

Solution: async-rails


I believe that a good solution to this problem is to use Rails engines and async-rails together.

Suppose we have an engine that implements a certain FooController with the #bar action:
moduleMyEngineclassFooController < ::ApplicationControllerdefbar
      render the: text => "Your text is #{params[:text]}"endendend


Add to the Gemfile:
gem 'thin'# yes, we're going to use thin!
gem 'rack-fiber_pool', :require => 'rack/fiber_pool'# async http requires
gem 'em-synchrony', :git => 'git://github.com/igrigorik/em-synchrony.git',  :require => 'em-synchrony/em-http'
gem 'em-http-request',:git => 'git://github.com/igrigorik/em-http-request.git', :require => 'em-http'
gem 'addressable', :require => 'addressable/uri'


And this line in config.ru:
...
use Rack::FiberPool # <-- ВОТ ЭТУ
run HmvcTest::Application


And here it is in config / application.rb:
...
    config.threadsafe! # <--  ВОТ ЭТОendend


Now we can make requests from any part of our application in FooController:
classHomeController < ApplicationControllerdefindex
    http = EM::HttpRequest.new("http://localhost:3000/foo/bar?text=#{params[:a]}").get
    render :text => http.response
  endend


Now start the server:
this start


and open http: // localhost: 3000 / home / index? a = HMVC in the browser:


In the rails log, we get: We made one request inside another. Everything seems to be ok!
Started GET "/home/index?a=HMVC" for 127.0.0.1 at 2012-02-03 15:27:02 +0400
Processing by HomeController#index as HTML
Parameters: {"a"=>"HMVC"}

Started GET "/foo/bar?text=HMVC" for 127.0.0.1 at 2012-02-03 15:27:02 +0400
Processing by FooController#index as HTML
Parameters: {"text"=>"HMVC"}
Rendered text template (0.0ms)
Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms)

Rendered text template (0.0ms)
Completed 200 OK in 6ms (Views: 0.4ms | ActiveRecord: 0.0ms)




Problems


This approach has several disadvantages:
  • there is no way to isolate the engine from requests from the outside world (everyone can make a request to FooController directly);
  • all logs are written to one file


References


  1. Scaling Web Applications with HMVC article by Sam de FreThe
  2. https://github.com/igrigorik/async-rails

Read Next