How to embed/mount existing Rails app into another Rails app? - ruby-on-rails

I have two Rails apps (using rails 3.0.7), call them "blog" and "auth". I'd like to mount "auth" from "blog" such that I can run the "blog" app and have certain requests routed to the "auth" app.
It seems like I need to embed or perhaps create an "engine", but I'm not 100% sure which is correct.
How can I embed the "auth" app inside of the "blog" app?

You can create "rails-engine" for 'auth' app, and then mount this engine into the rails application i.e 'blog' application.
Read more about Rails::Engine at below links -
http://guides.rubyonrails.org/engines.html
http://api.rubyonrails.org/classes/Rails/Engine.html
To embed a Rails mountable engine into a Rails application, follow these general steps -
1) Open the target Rails project, where an engine should be embedded.
2) Open for editing the Gemfile, and add the following line:
gem '<engine name>', :path => "<absolute path to the Rails mountable engine project>"
3) Open for editing Config/routes.rb, and add the following line:
mount <engine name>::Engine, :at => "/<engine name>"

Rails was raising RuntimeError: You cannot have more than one Rails::Application if you attempted to have two Rails apps defined in one Ruby instance, but it has changed after this commit.
This is still unreleased in 4.0.0, but will get included in the newer versions. (> 4.1.0.beta)
Check out the discussion on PR for more info.
From what I understand, you probably don't need to have two Rails apps, though. You should probably attempt to extract functionality you need in the Rails::Engine.
Remember, Rails::Application is also a Rails::Engine.
You can find a lot of material about how to do it on the web, and I would recommend these two to get you started.

Rails3 is a rack-based application. Rackmiddleware already has a number default built-in applications. Try to run bundle exec rake middleware. You can add custom Rack applications into the stack. Use this blogpost to see how it works.

If auth app is something like a web service (for example facebook authentication), so just keep 2 apps running and make requests from one app with urls to another app.
If these apps share some logic or the same database, you can just merge the code, so two apps become one, or your can make 'auth' app something like a gem or a plugin and use it in your 'blog' app.

Related

Automatic Reloading of Sinatra App mounted inside Rails App

I've run into what I hope is an easy-ish fix for someone more experienced than me when adding a Sinatra app to an existing Rails app.
I currently have a large rails monolith that I am planning to break apart into an SPA backed by a JSON API. Since I will still need to support the monolith until the API is completed I would like to mount the API (written in Sinatra) inside the existing Rails app as I port functionality over with a goal of removing the Rails app itself in a few months. The reason I've mounted the Sinatra app inside Rails instead of setting it up as a separate service was that I wanted easy code sharing between the two as I intend to continue using ActiveRecord as my ORM in Sinatra once the migration is complete.
I've mounted the Sinatra mockup inside the Rails app without any issues using the Rails routes.rb file as:
Rails.application.routes.draw do
mount API::Core, at: '/api'
...
end
I'm not doing any work with config.ru as mounting the API inside the routes.rb file seemed to suit my needs. If I need to put in some more legwork to get this running properly that is not an issue.
The entrypoint for the sinatra app is also fairly simple with just a couple controllers loaded in to segment the routing:
require 'sinatra/base'
require 'sinatra/json'
require_relative 'controllers/first_controller'
require_relative 'controllers/second_controller'
module API
class Core < Sinatra::Base
register Sinatra::FirstControllerApi
register Sinatra::SecondControllerApi
end
end
The problem I'm running into is one I expected with Sinatra but haven't been able to flex my google-fu enough to find a solution. Rails automatically reloads code on each change/request as expected but Sinatra does not. Every time I change controller code in the Sinatra API I need to restart the entire Rails server to serve the new content. Since my dev environment runs in docker containers this can take a while to start up each time and is becoming cumbersome.
Is there a 'canonical' solution to the problem of automagically reloading the Sinatra app mounted inside the Rails app or am I just over-complicating the problem? I know there are some gems for Sinatra that apply to this space but I haven't seen any info in how to get them working in this 'odd' edge case.
Please let me know if you need any more info, hopefully I've provided enough for someone to comprehend my issues.
Just like with a Sinatra app on it's own, a Sinatra app mounted inside o rails will not automatically reload as you make changes. Typically in Sinatra people would use external tools to help solve this problem, so they might set up something like Shotgun to watch the directory and restart the server any time a change has happened.
But, like most things in Rails, there is a way hook into it's functionatly for your own programming benefit.
ActiveSupport::FileUpdateChecker
Rails has a handy ActiveSupport::FileUpdateChecker that can watch a file, or a list of files. When they change it will call back to a block. You can use this to reload the Sinatra app -- or anything else for that matter.
In your case you might want to add the following to config/environments/development.rb in the config block for the application:
Rails.application.configure do
# ...
sinatra_reloader = ActiveSupport::FileUpdateChecker.new(Dir["path/to/sinatra/app/**"]) do
Rails.application.reload_routes!
end
config.to_prepare do
sinatra_reloader.execute_if_updated
end
end
Robert Mosolgo has a good write up on his blog: Watching Files During Rails Development. His approach is a little more thorough, but more complicated.

how to make a sinatra app run in rails 4?

I have a Sinatra app and I'd like to start building new functionality in Rails while still supporting the existing Sinatra functionality. I've tried the following strategies:
sinatra's rackup routes some requests to rails and some to sinatra
sinatra's rackup includes rails
rails' rackup includes sinatra.
Many of my searches resulted in rails 3, not 4. Additionally, does Rails have to generate the db versus using one that Sinatra was using (in this case, the Sequel gem to access Sqlite3.) In general the errors I was getting were about gems and paths. (Although I did rebundle and try different versions of paths.)
Any suggestions on the best way to use Rails 4 while still supporting an existing Sinatra app?
I don't think the Rails/Rack integration code has changed very much between Rails 3 and 4, so you should be fine. The Rails on Rack Guide explains in more detail that you can make a config.ru file for a Rails application that looks like:
require ::File.expand_path('../config/environment', __FILE__)
use Rack::Debugger
use Rack::ContentLength
run Rails.application
and then running rackup config.ru will start a rack server running your rails app.
The answers to this question point out that if you run Rails and Sinatra from Rack, rather than mounting your Sinatra app in Rails' routes.rb file, requests to your Sinatra app won't go through Rails at all. The answers also show that in your config.ru you should be able to do this to support both your Sinatra and Rails apps:
map "/" do
run RailsApp::Application
end
map "/url1" do
run SinatraApp1
end
You'll have to modify the routes and application names to match your needs and your applications, of course.
I'd recommend getting your apps running through one config.ru first, and then ask another question about your databases, explaining in more detail what you'd like the database setup to be and what the exact error messages you're getting are.
Rails does not need to create a database or even use one directly. To generate a new Rails app without ActiveRecord, run rails new APP_PATH --skip-active-record. Then, instead of using a database directly from the Rails app, send requests to the Sinatra app and have the Sinatra app control everything database-related.

Route to separate rack application on heroku?

Lets say I have a Rails app running on Heroku at www.myapp.com. I would like to create a separate Heroku application to serve a simple (Rack-Jekyll) blog for my Rails app but I would like this blog to be accessible at
www.myapp.com/blog/
Is there a way I merge the two apps together considering that they are both Rack based, but keep them as separate Heroku applications and separate git repositories?
You can use redirect method.
match "/blog" => redirect("http://myapp.com/blog")
No, this isn't possible (currently). You'll need to add the /blog as a gem or engine to the mainapp repository, and then push the combined repository to heroku.

Merging two rails apps

I have a main app and a forum app. I wanted to include forums in my main website. I manually copied all files from forum into my main app. I created proper routes and copied everything from db/migrate.
Now, I can see that everything is included and it works. But the problem is that whatever was originally stored in my forum apps that is questions and categories are no longer stored in the main app after merging. Its like a new copy.
Is there a better way to merge two rails apps along with stored data? or is there any way i can resolve this issue
You can adapt your forum application as a mountable app, follow this tutorial. I think this could be the best way to do that.
Also you can read pointers in this my previous question to get a general idea on rails engines: Differences between railties and engines in Ruby On Rails 3
Features like forums which are common across web apps can be built using engines which can be easily plugged into rails apps
If you want to share the data between 2 rails apps, you have to have a separate setting in database.yml and use establish_connection method inside the forums model in both the rails apps.
Click here to understand how to configure multiple databases in a rails application.
There you go:
https://github.com/adamwiggins/yaml_db
Install the plugin
rake db:data:dump
from the old database
rake db:data:load
to the new database.
Voila!

Running Rails as an embedded app inside of a gem

I'm trying to understand what exactly the above (in my question's Title) means? This is taken directly from the SpreeCommerce.com project:
If you’re an experienced Rails developer you may be wondering where your app directory is. Spree actually runs as an embedded Rails app inside of your gem. How do you customize things then? We’ll cover that later in extensions.
Source: http://spreecommerce.com/documentation/getting_started.html
Can someone further explain what exactly it means when a Rails app is run "inside of your gem"
With the gem spree, you can install your application and use it. A lot of application need download complete package to install it. When the gem spree, you don't. So it's more easier to install spree on your server.
The phrase you quote is poorly written and not particularly useful. What you should take away is that Spree is structured different from the majority of Rails plugins.
Typical plugin:
your rails app <-- plugin functionality
A Spree app:
spree rails app <-- your site specific code
Typically, most Rails plugins are installed in the vendor/plugins directory of your Rails app. Some additional functionality is added by classes and modules that you can then reference in your code (subclassing a ResourceController, for instance).
Spree does not work in this way. Because, presumably, there is so much configuration code for Spree, each Spree instance creates a separate Rails app -- one that's missing some of the more important parts of a Rails app (such as the app directory). All of your site specific code goes in the vendor/extensions/site directory. This means you don't have to worry about editing any of the Spree-specific code (since it's all in a different directory) and you can more easily put your own code under source control.

Resources