Overriding the Rails router - ruby-on-rails

This is a weird one I know. I'm trying to tie together two Rails applications, a v3 and a v2.3.5
I want them to share the same domain, and in order to do that without changing the URLs in the older app, I'm trying to find a way to override the Rails router.
I want the newer app living at the root of the domain, and the older one under several directories. For example:
/ => app1 # v3
/users => app1
/employees => app2 # v2.3.5
/payrolls => app2
So, since app1 lives at root and I'm using Passenger, I only have to create symlinks in the public folder of app1 to the public folder of app2, like so:
app1/public/employees => app2/public
app1/public/payrolls => app2/public
And then I add RailsBaseURI /employees and RailsBaseURI /payrolls to Apache's config.
With that I can make old URLs of app2 work, but inside the app, the links point to a prefix. For example, /employees/1, /employees/employees/1, /payrolls/employees/1 all work, but links in the app point to /employees/employees/1 and /payrolls/employees/1 depending on which prefix I'm currently on.
So, I need to remove that prefix from the links so only the old URLs work.
I need to do this in order to release the newer app. In time I'll upgrade the older one to v3 and work directly on this issue, but right now any hack is ok just to make it work.
I don't expect a solution, but if you can point me in the right direction on where to look in Rails source, or maybe a simpler approach I'm not seeing, I'd be very grateful.

Turns out it's pretty easy just by overriding url_for in the ApplicationHelper like so:
def url_for(options = {})
original = super(options)
# I tried this in order to improve performance:
return original unless original.starts_with?('/employees/employees')
original.gsub('/employees/employees', '/employees')
end
However, this caused intermittent errors in the app that I wasn't able to pinpoint. I suppose it's because of the performance hit.
So in the end I was forced to use a different domain for the newer apps.

I'm not really sure if that's possible to use 2 different versions of rails on your routes, but another way to do that is using haproxy with 2 different servers.
# In haproxy.conf:
frontend rails
bind *:80
acl rails2 hdr_host(end) -i employees.mydomain.com
acl rails3 hdr_host(end) -i mydomain.com
use_backend rails2_server if rails2
use_backend rails3_server if rails3
default_backend rails3_server
backend rails2_server
server myrails2_server 192.168.1.1:3000 check
backend rails3_server
server myrails3_server 192.168.1.1:3001 check
Then point your DNS A record of mydomain.com to your haproxy IP and point employees.mydomain.com to mydomain.com/employees.
To test it out, you can add the IP address of your haproxy server and mydomain.com to your /etc/hosts file

Related

Rails routing / assets with proxied location

OK so - I have a rails app, let's call it "railsapp", on a domain on a Dreamhost VPS (on which I have other domains, some 'static' and one that serves a perl/CGI script).
For obvious reasons, Passenger cannot be run on port 80, and is currently serving this app on port 8001. I have a proxy (configured in Apache) set up to route requests for http://DOMAIN/books to DOMAIN:8001/ (which, incidentally, works as DOMAIN/railsapp).
The issues:
1) No assets are served - the request for the stylesheets 404s, despite the fact that the stylesheets do in fact exist in [railsapp]/public/assets. I have tried every possible combination of precompiling, not precompiling, etc., and nothing seems to work.
2) Links aren't working exactly right. Accessed explicitly through port 8001, links work correctly, e.g., DOMAIN:8001/about shows the 'about' page and DOMAIN:8001/[railsapp]/[:id] brings me to the appropriate item. Similarly, accessed explicitly (i.e., by manually typing the address in the address bar), DOMAIN/books/[railsapp]/[:id] and DOMAIN/books/about work perfectly fine. But the links at DOMAIN/books (to the items identified by id) all point to DOMAIN/[railsapp]/[:id], which gives me a 404; the link to 'about', similarly pointing to DOMAIN/about, also does not work.
Now! If I were to throw caution to the wind and switch my VPS to use nginx instead of Apache, guess what? The pathing mostly works! Items identified by id are linked as DOMAIN/books/[railsapp]/[:id] and "about" is linked as DOMAIN/books/about, and this is great. The only issue in the rails app is that links back to root are inexplicably(?) rendered as links to 127.0.0.1:8001. This is annoying, but seems like it would be trivial to fix. The one problem with this is—you may remember this from the beginning of this post—the VPS also hosts a site that uses perl/CGI, and this is broken as hell given that nginx isn't really meant to deal with perl/CGI. As such, I'm sticking with Apache so that the CGI remains unbroken.
I have done the search for this issue, many times, in many different ways. I have probably seen whichever stackoverflow question or blog post you are thinking about linking me to. If you have any idea how to fix the pathing and assets issues, given the above information, let me know.
Try in application.rb inside "class Application < Rails::Application":
config.action_controller.default_url_options = {host: 'DOMAIN/books', port: 80}
config.action_controller.asset_host = 'DOMAIN/books'
config.serve_static_files = true # for rails4; for rails3 use .serve_static_assets = true
After that, restart your application.
Make sure that application uses *_url-helpers everywhere rather than *_path-helpers (i. e. root_url instead of root_path)

Linking Rails App and Wordpress Blog on different hosts

I have setup my Rails app on a VPS and a WordPress blog on GoDaddy. I did this because I don't want to have to install PHP on my VPS. Also, my rails app is using Postgres and while I am aware that WordPress can be setup to use Postgres, I just don't want to go through the hassle.
How do I link the blog and my rails app, such that the blog is located at:
www.mysite.com/blog
Also, when internally navigating on the blog, the base URL should remain www.mysite.com/blog
For example:
www.mysite.com/blog/article1
www.mysite.com/blog/category
And so on....
Assuming that your Rails site runs with an Apache in front, here is something you can put into the VirtualHost part of your Rails site:
<Location /blog>
ProxyPass http://godaddy.com/yourwordpress-site/
</Location>
In Nginx it would look like this
location /blog {
proxy_pass http://godaddy.com/yourwordpress-site;
}
Of course I would recommend, that you add some more options to the proxy setup so that the IP address of the original requester is kept etc. Doing it this way, the Webserver already catches the request and doesn't even bother your Rails app with requests that it doesn't really know about.
to redirect correctly, but not hide the url of the wordpress site
in your rails app's routes.rb
match "/blog" => redirect("http://YOUR_WORDPRESS_BLOG_SITE_URL")
Make sure you didn't forget to add http/https in your redirection url
Another alternative is to use a subdomain (instead of a subfolder), like blog.mysite.com, and then it can be handled using plain and simple dns.

can't log on to wp-admin when wordpress is hosted as a rails subdirectory

I have a rails app on heroku, and a wordpress-heroku install also on heroku. I'm using the rack-reverse-proxy gem to redirect my wordpress to the /blog directory on my rails app. I followed all the instructions here:
http://rywalker.com/setting-up-a-wordpress-blog-on-heroku-as-a-subdirectory-of-a-rails-app-also-hosted-on-heroku
When I access my wordpress blog on its normal address, everything works fine. However, when I have it set up under a subdirectory of my rails app, I can't log in. I go to wp-login.php I enter my credentials, get forwarded to /blog/wp-admin.php, and then immediately I am redirected back to /blog/wp-login.php?redirect_to=http%3A%2F%2Flocalhost%3A3000%2Fwp-admin%2F&reauth=1. The only cookie that gets set is the wordpress_test_cookie, but none of the other wordpress cookies make any appearance in my browser.
I have tried many things to fix this including using rack-reverse-proxy to forward all rails traffic to wordpress, so I don't have to use a /blog subdirectory in case that was causing the problem. But the exact same behavior results. I've also determined that the :preserve_host setting in the Rack::ReverseProxy config doesn't seem to make any difference whether it's true or false.
Ideas?
A) What do you have in your wp-config.php? Should be something like this:
define('WP_SITEURL', 'http://www.DOMAIN.com/blog');
define('WP_HOME', 'http://www.DOMAIN.com/blog');
B) In the Rack::ReverseProxy settings, are you pointing to the blog (wordpress) herokuapp.com URL, not the main site (rails) URL, right? I realize my post isn't clear on that point.
I finally tracked this down to a bug in rack-reverse-proxy. The set-cookie header was being sent in an improper format, so only the first cookie was being interpreted correctly by the browser. That happened to be the wordpress test cookie. All the other (useful) ones were being thrown away, so of course I could not log in.
I plan to submit a bug and branch to rack-reverse-proxy but in the meantime I fixed it with this patch in my config.ru:
class MyReverseProxy < Rack::ReverseProxy
private
def create_response_headers(http_response)
response_headers = super(http_response)
if response_headers
if response_headers["Set-Cookie"].is_a?(Array)
response_headers["Set-Cookie"] = response_headers["Set-Cookie"].join("\n")
end
end
response_headers
end
end
# this is to make /blog show my wordpress blog
use MyReverseProxy do
reverse_proxy_options :preserve_host => false
reverse_proxy(/^\/blog(\/.*)$/, 'http://your-blog-server.com$1')
end

How can I use a subdirectory instead of a subdomain?

I'm building a rails app that I'll host on Heroku at domain.com. And I'd like to use WordPress for the blog hosted on phpfog, but I don't want to use a subdomain like blog.domain.com. I'd instead prefer to use a subdirectory like domain.com/blog
Its not about SEO...I'm just not a fan of subdomains. Subdirectories are sexier (yeah...I actually said that).
Any idea on how I can reliably accomplish this? Thanks in advance for the help.
You can use the rack-reverse-proxy gem that neezer found to do this. First you'll want to add gem "rack-reverse-proxy", :require => "rack/reverse_proxy" to your Gemfile and run bundle install. Next, you'll modify your config.ru to forward the /blog/ route to your desired blog:
require ::File.expand_path('../config/environment', __FILE__)
use Rack::ReverseProxy do
reverse_proxy /^\/blog(\/.*)$/, 'http://notch.tumblr.com$1', opts={:preserve_host => true}
end
run YourAppName::Application
You probably already have the first require statement and the run YourAppName... statement. There are a couple important details that make this work.
First, when you add your desired blog URL, you can't keep the trailing slash on it. If you do, when someone requests http://yourdomain.com/blog/, the gem will forward them to http://you.yourbloghost.com// with an extra trailing slash.
Secondly, if the :preserve_host option isn't enabled, your blog hosting server will see the request as being for http://yourdomain.com/blog/ instead of as http://you.yourbloghost.com and will return bad results.
You still may have an issue with the CSS or images if the blog uses /absolute/paths/to/images/.
I'd say your best bet is to try and do a reverse proxy with Rack middleware (akin to Apache's mod_proxy).
A quick Google search revealed this gem ( https://github.com/jaswope/rack-reverse-proxy ), but the author mentions that it's probably not production-ready. Having a Rack middleware proxy should allow you to forward your subdomain yourdomain.com/blog to another website your-phpfog-account.com/wordpress-installation.
As far as I can tell you can't access the Apache config file with heroku if you could you could use a Rewrite rule.
If you choose not to use heroku you can always do what I detail below.. However if you're not using heroku you could just as easily extract wordpress to the /public/ rails folder and once again use a rewrite rule to get apache to handle the blog requests.
In your apache configuration you'll need to add.
RewriteRule ^/blog/?(.*)$ http://somedomain.com/~user/blog/$1 [P,NC,QSA,L]
It will redirect all requests to /blog/ to the other server.
Source: http://www.igvita.com/2007/07/04/integrating-wordpress-and-rails/
In addition to jplewickeless' answer, I ended up writing custom Rack middelware to replace absolute urls and other paths at the side of the reverse proxy. This guide will get you started on that:
http://railscasts.com/episodes/151-rack-middleware

Is there a way to change map.root to point to something other than '/'?

I have apache 2.2 with mod_rails running at http://localhost. I want to have my rails app at http://localhost/railsBlog. So, what I did was, I created a virtual host:
ServerName localhost
DocumentRoot /Library/WebServer/Documents
RailsEnv development
RailsBaseURI /railsBlog
Now, since the URL is http://localhost/railsBlog, the server views railsBlog as the controller I'm passing in, which is not what I want. So when I go to http://localhost/railsBlog/home/index. This won't get to my 'home' controller and 'index' view because it tries to go to 'railsBlog' controller (doesn't exist) and 'home' view (doesn't exist).
I think one way to solve this is to redefine map.root to be /railsBlog and things should be fine. But how?
Another way I could get around this would be to modify config/routes.rb to have:
map.connect 'railsBlog/:controller/:action/:id'
However, this would mean that I would have to change this file every time I deploy to a different location.
Or, is there any other way to get around this?
You can put a line like this in config/environment.rb (or one of the specific environment files)
config.action_controller.relative_url_root = "/railsBlog"
You should also symlink the publc directory to the root of the web directory, for example:
ln -s /rails/railsBlog/public /webroot/
This is all from the passenger documentation
Just to add to the previous answer... here is the url of the documentation:
http://www.modrails.com/documentation/Users%20guide.html#deploying_rails_to_sub_uri
Also, here is some information if you are running into errors with broken image, css, resource links...
http://www.modrails.com/documentation/Users%20guide.html#sub_uri_deployment_uri_fix
Basically it says you should always use the rails helper functions (image_tag, javascript_include_tag, and stylesheet_link_tag) instead of hand coding the urls. These will automatically generate the correct URL with the sub uri you have set.
This allows you to easily move the application to another sub uri or out of the sub uri configuration without changing all of your references.
One nice thing about this is that you can use one virtual server statement to deploy mutiple applications by having multiple RailsBaseURI lines. This came in handy for an app we were trying to build.

Resources