Yo dawg, I heard you like…

Purely theoretical (obviously) case: you have existing php app and some legacy rails code that you refreshed a little bit and now someone asks you one simple question - why can’t you just put that code into that code and run it as one app? Sometimes you can reason, sometimes not. But let’s do it - I mean seriously - let’s create some kind of hybrid that will work transparently and silently for the user. Unleash your imagination and get ready for breaking every programming paradigm; treat it like a sport and get ready :).

Let’s ever get a little bit further, let’s create one rails app that will distribute its content for two different domains. Where do we start?

I assume you have some kind of working application already, in the end we want to have:

Moreover we want to create this whole structure in a way that it can be ran as separate apps in the future just in case.

First - get familiar with mod proxy as I’ll be using Apache here with with phusion passanger. I think the most reasonable approach is to handle two different sub-domains for serving content (plus admin namespace for backend).

So looking at our application it would look like:

Be aware that I can’t provide where working example as solutions may vary quite a lot depending on structure of your existing applications and need, but I will give you some ideas if you will need to (theoretically) create that kind of hybrid someday.

Configure phussion passanger for your rails app, don’t forget to set PassengerFriendlyErrorPages on and RailsEnv "development" for now.

Now it’s time to start some proxy-action in your php app, setup in your virtual host config:

ProxyPass /superapp1 http://superapp1.rails.app
ProxyPassReverse /superapp1 http://superapp1.rails.app

ProxyPass /superapp1 http://superapp2.rails.app
ProxyPassReverse /superapp1 http://superapp2.rails.app

In your rails routes on the other hand you have to handle those sub-domains, after reading/watching this railscasts I ended up with:

# config/routes.rb
  ...
  constraints(Subdomain) do
    # some resources and stuff
  end
  ...
  namespace :admin do
    # and here some controllers for handling backend
  end
end

and:

# app/lib/subdomain.rb
class Subdomain
  def self.matches?(request)
    %w(superapp1 superapp2).each do |subdomain|
      return true if request.env['SERVER_NAME'] =~ /#{subdomain}/
    end
    false
  end
end

After reloading apache cofiguration (service apache2 reload) loading address /superapp1 from php app should bring on your brand new ror app.

Its not especially exciting and you may noticed some serious problems here:

Lets stard from fixing those urls, one way is to overload url_for method from UrlHelper. I ended up with something like that:

# app/helpers/url_helper.rb
module UrlHelper

  def url_for(options = nil)
    options[:host] = "#{request.domain}/#{subdomain_from_server}" if options.kind_of?(Hash) && !subdomain_from_server.empty?
    super
  end

end
# app/controllers/application_controllers.rb
class ApplicationController < ActionController::Base
  include UrlHelper
  helper_method :subdomain_from_server # allow with method for views (UrlHelper)

  protected
    def subdomain_from_server
    %w(superapp1 superapp2).each do |subdomain|
      return subdomain if request.env['SERVER_NAME'] =~ /#{subdomain}/ # as it's proxied we have to get subdomain from server
    end
    ''
  end

 end

Now when you call eg. articles_path or whatever you should end up with pretty proxy-ready url (that will be broken when you run your app as-it obviously).

I decided to filter content just by using CanCan (once again thank to Ryan) and setup access depending on current sub-domain in ApplicationController (you can use can and cannot on current_ability).

What’s left is authentication - how to setup backend access, log-in curret users - and that’s whole different subject. I will point three things here:

Well, that’s it - very generall idea how it can be done, hope you liked this little piece of dark hackery ;-).