I'm trying to host multiple rails apps for my blog. Kind of like www.blog.com/app1 will have one rails app, www.blog.com/app2 will have another. How do I do it?
Although I agree with downvotes as pointed out by the first comment, I had this problem myself several months ago and actually didn’t even try to solve it as I realized how many implications this has. Existing answers on Stack Overflow address either slightly different or narrower issue so they may use some things mentioned here but don’t elaborate on implications or alternatives, yet there’s an interesting overview (and also other answer to that question). Anyway, I took it as a challenge and dived in.
First, there are multiple approaches depending on your scenario:
All applications are code which you maintain – it’s probably the best to explore something called engines. They are like mini RoR applications mountable to certain path within normal RoR application. It has many benefits like sharing the same runtime or simple isolation configured in on place.
If there are no AJAX with URL or similar dynamisms or that they are actually AHAH (i.e., asynchronous HTML and HTTP – returning HTML fragments instead of XML or JSON data) which is very natural for Rails although often not used, you can use sophisticated proxy modules like mod_proxy_html which rewrite links inside HTML documents while proxying. Similar modules exist for nginx but are not part of standard distribution.
RoR has a configuration option relative_url_root which allows deployment to subdirectories. It’s very fragile and often buggy, many gems or engines break when you use it, so beware. When you get it right, it looks like magic. However, your configuration relating to subdirectory will be scattered throughout different software configs and your code.
I created an example repository while exploring the last option. README should say everything necessary to run the code.
The most important observation from this small project is that when using relative URL root, you almost certainly want to scope all your routes. There are different setups possible, but they are even more complicated (which doesn’t mean they don’t make sense). For examples see the answer with overview mentioned above.
By default (without scoped routes), only asset paths are prefixed with relative URL root, but not action route paths even though it makes URLs generated by helpers useless unless translated by mod_proxy_html or probably more custom solution.
Other important observation, which relates to official guide, code “out there” and answers to similar questions here on Stack Overflow, is that it’s good to avoid forward slash at the beginning of relative URL root. It behaves inconsistently between tests and the rest of the code. Yet it can be used nicely around your code – see scope definition in routes config or dummy controller test case.
I got to these and other observations by creating two very simple and almost identical Rails 5.2 applications. Each has one action (dummy#action) which has a route scoped to relative URL root. This action, or its view specifically does two important things to verify that everything works:
it outputs the result of calling root_path helper which shows we have correctly setup URL/path helpers (thanks to scoped route in config/routes.rb)
it loads static asset which isn’t served by Rails application but directly by Apache HTTP Server and which is referenced by image_path helper
You can see that virtual host configuration has rather extensive list of URLs which shouldn’t be passed via proxy and rely on aliased directories. However, this is application specific and very configurable, so simpler setup with different directory layout is definitely achievable but entirely separate topic.
If you like Passenger and don’t want to use proxying in your HTTP server, you can find more information in their deployment tutorial.
Related
So, we want to rearchitect a portion of our site as a Rails app. The original plan was to have a main "site" app, with a number of plugin apps (Rails 3.1 Engines) with compartmentalized functionality -- a store component, a social/forums/chat component, etc. Also, we wanted to put themes/styling in a gem so that our web designers could modify the site appearance and some minor layout tweaks without having to "know Rails." Initially, this was going well; we created the main architecture and plugins and the theme gem, and it was all playing nicely together; cross-cutting functionality like auth was put in the main "site" app and was consumable by the plugin apps, giving us a single sign-in for the site (a design requirement).
Our initial plan for the store component was to use the Spree (http://spreecommerce.com/) since it had, out of the box, 95% plus of the functionality we needed. However, there's a catch -- Spree is distributed as a mountable engine, but it's also an app. Meaning that not only does Spree mount inside an app (which is not a problem, in fact it's behavior we were counting on), but it depends upon being in control of the main app. Looking into the "why" for this behavior, it seems to depend upon two core pieces of functionality. The first chunk of functionality is some SEO permalink rewrite functionality that has to go into middleware; we could hack things so that our main app included this chunk of code (even though this would begin to entangle store functionality across our entire site, muddying the "Spree as a mountable engine" story... more on that in a moment).
More complicated is Spree's use of Deface to do theming and customization. While this is "clever" (note quotes), it really makes the integration of Spree kind of a nightmare; either you follow the path of least resistance and make Spree an entire store to itself (which completely breaks our story of "the store is just one part of our site, and plays nice with the rest of the site, including auth, theming, etc."), or you have to hack the hell out of Spree.
Not only that, but Spree doesn't follow the standard Rails Engine routing paradigm, where routes are isolated beneath an engine root (if you look in the lib's routes.rb file, you can see that it uses Rails.Application's routes, instead of an Engine's routes). This means that we couldn't have www.oursite.com/store/...all_the_spree_goodness, we'd have to have www.oursite.com/spree_owns_the_sites_routes...
So, has anyone else tried this? We LOVE Spree and would like to use it as our store. But it's starting to look that there's no real way to "integrate" it with the rest of our site aside from maybe some proxying magic with nginx or something like that (which is a separate nightmare, since we're hoping to host on Heroku, and then we have to figure out how to integrate multiple disparate apps into one DB -- for single sign-in auth -- and an HTTP front router).
Spree devs, we LOVE your code, but is there any work being done to make it an actual, for-real Rails Engine, as opposed to a stand-alone app that just happens to package all of its features into Engines? Without the ability to integrate it into an existing site (including not "owning" the app, being able to have all of its routes partitioned off, and so on), there's just no way we can use it :(
TIA.
I'm the Community Manager for Spree, so I think I may be able to answer your question.
Yes, there is work going on that will allow Spree to be a true Rails engine. In fact, that was my first task that I did when I was hired by Spree. The work is on the master branch (https://github.com/spree/spree) and we're looking to release this code as a 1.0.0.rc around Christmas time.
With this code, a couple of changes have been made. For starters, Spree is now a proper Rails engine meaning that you can now have it mounted at /spree or /shop or /whatever and Spree's cool with that. Secondly, all the models and other classes are namespaced so they won't conflict with anything in your application.
I'm not sure what you mean about Deface being "clever", though. What problems do you forsee with this? If you want to override an entire view you could do this by overriding the path in app/views/spree/products/show.html.erb. Mind you, this overrides the whole view, and if you only want to override a part of it that's when you'd use Deface.
Could you perhaps elaborate on the issues you're having with Deface? Would be interested to help you sort them out.
Thanks for using Spree!
I am a rails developer working on a cakephp site. The more work they send me, the more php code I write and thus the more dependence on php we introduce. What I want is to stop writing new features in php and start writing them in rails. Our resources are limited and the existing php site is huge so a full port from cake to rails is not possible.
Is there some way to write new features in a rails app while maintaining and allowing access to all the functionality of the old php (and vice-versa)?
It seems I would need a route aware app to traffic requests to either php or rails, but then we run into the issue of, for example, existing user functionality written in php not being available to the rails app and vice-versa.
What about something to translate ruby into php? That way I could start writing my model stuff in ruby/rails rather than php.
I feel like my question is muddled by the fact I do not know how to ask the questions I want to answer, so hopefully this is understood.
As always, thanks in advance!
One approach that you may find useful is to leverage the power of your web-server to properly re-write and delegate requests to two different systems. If you can design your new Rails application to use the same database records as the old one, with models mapping to the old tables directly, and ensuring that sessions established by one are valid in the other, you have a lot of latitude in how you go about doing this.
Apache has a very full-featured URL rewriting and proxying system that can be configured to direct "legacy" parts of your site to an existing set of PHP scripts while directing all other traffic to the new Rails application. You will need to be careful to ensure the design of both applications are nearly identical or it may seem strange to users.
Another approach that helps ensure a consistent appearance is to strip out a lot of the theme from your PHP application. By creating very bare-bones pages that only expose the required functionality on each page, Rails can fetch these by passing through any relevant session authentication information and re-frame them in the right layout.
This way you can preserve existing functionality and have it embedded inside your new application. You can use something as simple as open-uri or the curb gem to handle this HTTP-level delegation.
You would end up with controllers that look like this:
class PaymentController < ApplicationController
def index
#content = fetch_legacy_url('/payments/index.php'))
end
end
The fetch_legacy_url method would create an HTTP fetch request that includes the required headers, cookies, and so forth, and return the response body. Your view then ends up looking something like this:
<%= #content =>
From there you can shunt parts of the PHP layout over to the Rails app piece by piece. For instance, ripping out large chunks of static HTML and putting them in the Rails template would reduce the amount of actual PHP code you have to port.
It's a bit messy to maintain two applications in parallel, but as you point out the alternative is to keep accumulating technical debt and making the inevitable re-write that much more significant an undertaking.
The first step would be to experiment and see if you can create a Rails environment that uses your existing data, or at least the data relevant to the new functionality you intend to build out.
What's the best way to organize multiple, slightly-varied incarnations of one Rails app?
The incarnations vary on css, images, database and domain. The app/logic is otherwise exactly the same. There is a chance public-facing path names of some routes will need to vary, but still the same route structure.
So I'm thinking of having one installation of the app and managing these changes in the environment.
DB is obviously already set up nicely for this. CSS and image paths I imagine would be easy enough to make environment-aware. Routes shouldn't be too difficult either I guess, in theory anyway.
The reason I'm writing this post is because I'm sure this problem must been solved. Is there an existing "skins" gem or something I can use for this? Otherwise, any comments on my planned approach would be greatly appreciated! I'm using Rails 3.
Why not just maintain separate branches in your revision control system?
A lot of it depends on why you're trying to achieve this. We currently serve four different 'apps' on a few different domains and subdomains from the same Rails Application. We do this because we have different clients that want to see different features of our product. For instance every product shares the idea of customers, contracts, merchants and many other models but they want to have the site branded differently, tab and menu items named differently and have some parts of the site inaccessible to certain people.
You've outlined CSS and images as your main concerns so I'll stick to those, however we've also had to employ ideas to remedy layouts, authorization and javascript amongst other issues and resources.
For simplicity sake I'll call a skin what in our case is a separate product.
Our app has a plugin that sets up some environment variables based on the incoming domain. Then based on these variables our Rails app will source different layouts and partials as appropriate. These layouts then reference the appropriate JS and images which are stored in locations that make sense for designers and frontend devs. For instance customer.js may store the usual customer operations, then in a sub directory there may be a customer.js for a skin and it will extend the main customer.js file (we use Dojo to do this).
In other areas where security is a concern we have libraries that do what is required based on the environment variables that were set by our domain gem.
We also have to provide dynamic branding so again these views and layouts have helpers with logic in them to determine where images should come from and so on.
For CSS we use SASS, so a lot of the time you can use mixins for colours and images. We do this by having a root SASS file with layout information that uses variables for colours and images. Then we'll require those colour files and image files into the root SASS as required.
The answer may be better if you give some information on how you are determining between these two skins. As far as I know there are domain plugins out there already that could help you determine which site the user is trying to access. As for how to organise your application to render the correct CSS, images, JS and so on hopefully what I've outlined helps a little.
I am looking at implementing URLMapping for a personal project. I am already aware that solutions exist so please do not answer suggesting I should use one.
What I want is to harvest the opinions of fellow developers and web users on URL mapping implementations. Specially I would like you to answer:
Which is your favourite implementation?
What do you like about your favourite implementation?
What do you not like about your favourite implementation?
How would you improve it?
I would like you to answer from two points of view:
As a developer
As a user
I would be grateful for any opinions on this matter, thanks!
I've only worked with django's URLConf mechanism. I think the way it relies on the urlpatterns variable is a bit flimsy, but I like its expressiveness in specifying patterns and dispatching to other url configurations. I think probably the best thing is to figure out your URL scheme first, and then try out a couple of solutions to see what matches best. If you're going hard-core REST using the full complement of GET/POST/PUT/DELETE, and checking the user agent's Accept headers, and all that, django will, by default, have you splitting your logic between URL config files and view files, so it might not be the cleanest solution.
However, since it's all Python, you might be able to do some more complex processing before you assign to urlpatterns.
Really, you want a system that does what you need. Your URL scheme is your API, so don't compromise on it based on the tools you use. Figure out your API, then find the tools that will let you do that and get out of your way.
Edit: Also do a google search for "URL scheme design." I found this without much effort: http://www.gaffneyware.com/urldesign.htm. Not comprehensive, but some good advice gotten from looking at what flickr does.
Well, I should have noticed the url-routing tag shouldn't I? :-) Sorry about that.
jcd's experience mimics mine - Django is what I use too.
I like the fact that the routes for an app reside within the app (in urls.py) and can just be included into any projects that might make use of that app. I am comfortable with regular expressions, so having the routes be specified in regex doesn't phase me (but I've seen other programmers scratch their heads at some more uncommon expressions).
Being able to reverse a route via some identifier (in Django's case by route's name) is a must. Hardcoding urls in templates or controllers (view in Django) is a big no-no. Django has a template tag that uses the reverse() method
The one thing I wish I could do is have the concept of default routes in django (like Rails does or even Pylons). In Django every route has to map to a view method, there is no concept of trying to call a certain view based on the URL itself. The benefit is that there are no surprises - your urls.py is the Table of Contents for your project or app. The disadvantage is that urls.py tend to be longer.
I'm a student of web development (and college), so my apologies if this comes off sounding naive and offensive, I certainly don't mean it that way. My experience has been with PHP and with a smallish project on the horizon (a glorified shift calendar) I hoped to learn one of the higher level frameworks to ease the code burden. So far, I looked at CakePHP Symfony Django and Rails.
With PHP, the URLs mapped very simply to the files, and it "just worked". It was quick for the server, and intuitive. But with all of these frameworks, there is this inclination to "pretty up" the URLs by making them map to different functions and route the parameters to different variables in different files.
"The Rails Way" book that I'm reading admits that this is dog slow and is the cause of most performance pains on largish projects. My question is "why have it in the first place?"? Is there a specific point in the url-maps-to-a-file paradigm (or mod_rewrite to a single file) that necessitates regexes and complicated routing schemes? Am I missing out on something by not using them?
Thanks in advance!
URLs should be easy to remember and say. And the user should know what to expect when she see that URL. Mapping URL directly to file doesn't always allow that.
You might want to use diffrent URLs for the same, or at least similar, information displayed. If your server forces you to use 1 url <-> 1 file mapping, you need to create additional files with all their function being to redirect to other file. Or you use stuff like mod_rewrite which isn't easier then Rails' url mappings.
In one of my applications I use URL that looks like http://www.example.com/username/some additional stuff/. This can be also made with mod_rewrite, but at least for me it's easier to configure urls in django project then in every apache instance I run application at.
just my 2 cents...
Most of it has already been covered, but nobody has mentioned SEO yet. Google puts alot of weight on the URL itself, if that url is widgets.com/browse.php?17, that is not very SEO friendly. If your URL is widgets.com/products/buttons/ that will have a positive impact on your page rank for buttons
Storing application code in the document tree of the web server is a security concern.
a misconfiguration might accidentally reveal source code to visitors
files injected through a security vulnerability are immediately executable by HTTP requests
backup files (created e.g. by text editors) may reveal code or be executable in case of misconfiguration
old files which the administrator has failed to delete can reveal unintended functionality
requests to library files must be explicitly denied
URLs reveal implementation details (which language/framework was used)
Note that all of the above are not a problem as long as other things don't go wrong (and some of these mistakes would be serious even alone). But something always goes wrong, and extra lines of defense are good to have.
Django URLs are also very customizable. With PHP frameworks like Code Igniter (I'm not sure about Rails) your forced into the /class/method/extra/ URL structure. While this may be good for small projects and apps, as soon as you try and make it larger/more dynamic you run into problems and have to rewrite some of the framework code to handle it.
Also, routers are like mod_rewrite, but much more flexible. They are not regular expression-bound, and thus, have more options for different types of routes.
Depends on how big your application is. We've got a fairly large app (50+ models) and it isn't causing us any problems. When it does, we'll worry about it then.