How to do URL rewrite in Rails? - ruby-on-rails

I have a rails app that is accessible through multiple URLs, I was wondering what is the best way to rewrite the URL to use the main domain name, abc.com.
I have a bunch of other domain names like
1kjsdf.info
2lksjdfs.info
3sldkjfds.info
... in total 50 of these kinds of domains.
They all end in info if that makes it easier. I used lighttpd as my webserver, is there a way to set things up so that when the user goes to 1kjsdf.info\profile, the url is rewritten as adc.com\profile?

You should probably do this in lighttpd, not Rails.
http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModRewrite
It will be much faster to service these requests in the HTTP server before letting it get to Rails.

Related

Rails APIs and path based load balancer routing

We're breaking our monolithic Rails application in to microservices. Our services are hosted on AWS and are behind ALBs. We cannot use host based routing as we are multi-tenant via subdomain, and it would be an SSL nightmare to maintain the required certs for each tenant/environment/service combination. So we are using path-based API routing with rules on the load balancer. A request looks like this:
Client -> www.example.com/api/:service_name/the_rest_of_the_path -> ALB -> route to rails service by name of :service_name
Because ALB cannot modify the path of a request before it sends it on to the serive, when it reaches the Rails services the path is still /api/:service_name/the_rest_of_the_path . This means in order to route to the proper controllers/actions in this case, we'd need to actually create a rails scope on namespace of /api/:service_name . This would work in theory but it has two drawbacks.
Firstly it means local developers have to deal with ALB/client specific concerns -- the path used for external service/cluster routing for ALB.
The second is that it couples the application to that path. If the load balancer decided the path should be /:service_name/the_rest_of_the_path instead then it would mean changing the application code in conjunction with the load balancer rules to accommodate it. It's not optimal and I'd prefer to avoid it if at all possible.
I thought then perhaps we could introduce a webserver to the mix, in between the load balancer and the application layer. I worked on a proof of concept for this and had it stripping out /api/:service_name before it got to the service -- leaving the Rails app with just "the_rest_of_the_path" which is all it cares about. Great! Perfect! Or so I thought.
It works well enough to route initial requests to, It however falls flat when any sort of redirects or links are used by taking the current path (as Rails sees it) in to consideration.
In the event /api/:service_name is stripped off before it hits the service, any subsequent links or redirects made from the Rails server itself naturally do not include it in there any longer. You may be on www.example.com/api/:service_name/foo/bar but Rails only thinks you're at /foo/bar. When it tries to tack something on to the path for a redirect or link like /foo/bar/baz, it loses the thing that identifies what service to send it to so the route dies at the load balancer.
This has particularly been an issue with Omniauth/Oauth2 flows for us. Omniauth wants to live at /auth/:provider by default. If the request path is actually /api/:service_name/auth/:provider then it won't match and the Oauth flow wont initiate. Further if there is a failure with the Oauth flow, Omniauth will hard redirect to www.example.com/auth/failure -- which of course does not resolve as the LB does not know where to route the request to.
If we provide a path_prefix to Omniauth as /api/:service_name/auth then it wont match when testing locally at /auth and it won't initiate the flow there.
We won't have control over all of the gems we use and where they redirect to so my question is: Is there a proper way of hanging Rails API microservices off a path on a load balancer, and not have to pull teeth to preserve the necessary prefix in all routes and links and redirects? Something that is essentially a global base href that we can set there, but not set locally so that we can continue to develop at localhost:3000/path instead of remembering to use (and coupling with) an LB path like localhost:3000/api/:service_name/path ?

Can I hide the domain name in the URL (in my Rails application)?

I have a Ruby on Rails application where my customers should ask their customers to go. But I would like to be able to hide/mask my own domain name from the url, so the customers of my customers don't feel like they are on a 3rd party website.
For example, if my domain name is:
https://app.example.com/visit/:customer_id
then what is my options for masking the example.com part?
If it is not possible to mask the domain name (I can see that even by using the IP address directly, https errors appear), then is it possible to put in some prefixes like e.g.:
https://prefix.app.example.com/visit/:customer_id
https://app.prefix.example.com/visit/:customer_id
https://app.example.prefix.com/visit/:customer_id
Btw, it's not important to keep the https security on these pages particularly, but I don't suppose it is possible to have an application that has both encrypted and non-encrypted pages?
your customers will have to setup their DNS to point to your application. you can use a CNAME to accomplish that. this can be done by using a subdomain.
if you use SSL/HTTPS you have to make sure that the certificates match the domain.
like #lassej already pointed out, an iframe is probably a better way of integration. it has several limitations though.

Rails app for multiple domains

I need to create a service with the same five sites and one that will unite them, but everyone has to live on a separate domain. Maybe somehow run one instance Rails app redirect users depending on the domain? Or is it better to start on a new Rails app per instance?
Why not just set up one instance of the rails app, and configure your http server (Apache, Nginx or whatever) to listen to connections on all of those domains?
Genarally, there are two ways you can do that with one rails instance.
redirect the comming requests to diffrent uri path ('/site1', '/site2' etc) from the http server based on the domain names. I'm not a pro on setting up this. But i'm sure this is do-able.
redirect the comming requests to different path from the application controller in a before filter based on the value of request.url.host variable.
redirect_to my_site1_path if request.url.host == 'www.site1.com'
You can choose either of them, it's up to you :).

How do I serve multiple rails apps on one domain (and sub)?

This is kind of weird but I'd like to serve multiple websites on the same domain. If possible, we want to avoid subdomains to keep urls simple for our users - no need for them to know it's two separate apps. This is purely for keeping the code bases separate. Any ideas?
For example:
Rails App 1 (Refinery CMS) serves:
http://example.com/
http://example.com/about
http://example.com/pricing
Rails App 2 (our real App) serves:
http://example.com/account
http://example.com/store
http://example.com/listings
We use ruby 1.9.2, ruby on rails, refinery cms, apache and passenger.
If you're using Passenger, check out the Deploying to a sub URI portion of the manual - it's quite simple to set up an app on a sub-URI. You may need to set config.action_controller.relative_url_root in your app configuration, as well.
Edit: I misread the question; not one app per URI, but one app serving some (but not all) endpoints. This is actually moderately easy to do with some basic rewrites, as well.
Deploy your Rails app to, let's say, /railsapp (but without setting relative_url_root). Now, in .htaccess:
RewriteRule ^account/(.*)$ railsapp/account/$1 [L]
This will internally remap /account/* to /railsapp/account/*, so as long as you set up a rewrite per path your Rails app handles, it should work fine.
Subdomains make it easier (thus why most sites have shop.example.com), but you could probably use rewrite rules with name based virtual host routing. How exactly to do that I'm not sure. More of a Apache rewrite question for SuperUser.
A word of warning if you are using SSL you might have issues arise.
You could set it up to first hit one app where you expect most URLs would work and if it 404s you could instruct it to try the other app next, though this will be slower than routing per route but it will work without having to hardcode a route for every page that is created on say, Refinery CMS.
Currently I'm also working on a same kind of CMS. In my case also I need multiple sub domains, like
www.test1.mydomain.com
www.test2.mydomain.com
www.test3.mydomain.com
www.test4.mydomain.com
here is what I did
in rails 3 (if you are on rails3) you can get the sub domain by using request object. (If you are on rails 2.x you can use sub domain_fu plugin)
In my case I have used a before filter to get the sub domain, after that I load the site according to the sub domain
For development use the following public domain "lvh.me"
http://tbaggery.com/2010/03/04/smack-a-ho-st.html
this was very useful for me http://railscasts.com/episodes/221-subdomains-in-rails-3
let users have their domains forwarded to your subdomain (with masking)
ex : www.clientdomain.com --> http://client.mydomain.com
hope this helps
cheers
sameera

Mapping multiple domain names to different resources in a Rails app

The rails app I have allows users to manage holiday homes. Each property has it's own
"website/homepage" within my app and a user can tweak the content, it works well,
quite pleased so far. Typical rails approach to the resources so the URLs to a particular property look like this for the "homepage" of a particular property.
localhost:3000/properties/1/
then
localhost:3000/properties/1/full_details
localhost:3000/properties/1/price_list
etc
Requirement is to map a domain name e.g. www.chalet-yeti.com and have it resolve (rewrite?) to localhost:3000/properties/1/
like so also...
www.chalet-yeti.com/full_details -> localhost:3000/properties/1/full_details
The next user adds a property and I register a new name on their behalf and I'd like to do this of course..
www.apartment-marie.com -> localhost:3000/properties/2/
Is this possible/advisable/doable in the same rails app? So far solutions have ranged from "why would you do that" to variations on "use mod_proxy / mod_rewrite / virtual_host config". In case it matters the app runs under apache and passenger on my server.
I don't want to pre-empt an answer but most people so far seem to point to apache configuration and most say what I'm attempting is not impossible / inadvisable. Really hope someone could at least point me in the right direction as I've been head scratching all morning. Out of my comfort zone here and I'm hoping I can launch my app and haven't spent six weeks building a white elephant! Unless I can do this URL thing, it's dead!
http://37signals.com/svn/posts/1512-how-to-do-basecamp-style-subdomains-in-rails
This is what you want. Don't mess with apache for that. It doesn't scale to hundreds of domains and it's prone to breakage.
Within Rails, you should think of the requests coming just to a URI, without a host name section. That is, instead of localhost:3000/properties/1/full_details you need to think of /properties/1/full_details. The localhost:3000 part is just to get the request to Mongrel during the development process.
So what you really want is to take the request as it is received by the HTTPd (Apache, in your case) and extract some information to construct the request which is given to Rails.
mod_rewrite, which is an Apache module, is the sane way to do this.
You need to ensure that the same virtual host which runs your Rails application accepts requests for all the domain names you're using.
Then you can use mod_rewrite to do something like this:
RewriteCond %{HTTP_HOST} ^(www.)?chalet-yeti\.com$
RewriteRule ^(.*)$ /properties/1/$1 [L]
This will take every request to the host chalet-yeti.com (or www.chalet-yeti.com) and hand them to Rails as "/properties/1/$1" (where the $1 is any additional path, like full_details).
You'll need a block like that for each of your domains, but that's just two lines in your Apache configuration. Unless you're doing hundreds of domains, it should be tolerable, right?

Resources