What's the "Rails Way" to create route helpers to other hosts? - ruby-on-rails

My app consists of two rails servers with mostly different concerns sitting behind a reverse proxy. Let's call them Server1 and Server2. Occasionally, Server1 needs to render a link to a url on Server2. Is there a good way to use Rails route helpers for this? Specifically in Rails 2? I came up with this:
ActionController::Routing::Routes.draw do |map|
# other routes omitted
map.with_options(:host => 'server2.example.com') do |add|
# create a named route for 'http://server2.example.com/thingies'
add.server2_thingies '/thingies', :controller => 'fake'
# create a named route for 'http://server2.example.com/thingies/combobulate'
add.enhance_server2_thingies '/thingies/combobulate', :controller => 'fake'
# create a named route for 'http://server2.example.com/mabobs/combobulate'
add.enhance_server2_mabobs '/mabobs/combobulate', :controller => 'fake'
# etc..
end
end
So then I can use server2_thingies_url and such in my views. This works, but it makes me feel like a bad person because there is no FakeController and I certainly have no intention of routing requests to it. I considered making helper methods and placing them in app/controllers/application_controller.rb, but a colleague made the argument that it is best to keep all route helpers in routes.rb, so things like rake routes will be accurate, for instance. Is there a better way?

I think I'd make a counter-argument to your colleague: if you're having to dirty up routes.rb with a "FakeController", then your rake routes is still not going to be accurate. In fact, I'd say that this is exactly the kind of thing that a helper was meant to help: it's taking logic that belongs purely in the view (link generation), and removing it from your view templates. Helpers are also easier to maintain and tweak.
Another advantage to the helper style is that if and when it's time to upgrade to Rails 3.x, the less hackish your routes.rb file is, the happier you will be - and that I can attest to from experience. :)

I'd just pass in :host to your foo_path or foo_url calls.
Seems cleaner than messing around with a FakeController

Related

Rails URL and Path Helpers in Engines Like Spree

I'm trying to use some URL and/or path helpers in my Rails 4 Engine views such as resource_url or resource_path. These engines are configured a bit differently than the typical --mountable tutorial out there. In fact, they more closely resemble how Spree does it, without the Spree::ENGINE_NAME namespace.
Like Spree's architecture, I'm attempting to create core engine that my other engines depend on. For example, my backend engine's routes.rb file looks like this:
Core::Engine.add_routes do
# Check to see if the request comes in on a subdomain
# The Subdomains class passed into constraints()
# is a class defined in lib/subdomain.rb
constraints(Subdomain) do
match '/manage' => "manage#index", :via => [:get]
end
end
In a view inside my backend engine, I'd like to be able to use some URL/path helpers to do something like this:
<%= link_to manage_path, manage_path %>
This doesn't work, because I'm drawing the routes on the core engine. So, I must use
<%= link_to core_engine.manage_path, core_engine.manage_path %>
Spree somehow gets around this, but I'm not sure how. For example, in backend/app/views/spree/admin/products/index.html.erb:
<%= link_to product.try(:name), edit_admin_product_path(product) %>
Notice, the edit_admin_product_path, but no mention of this actually being drawn on the core engine.
Any ideas?
We get around this by drawing all the routes on the core engine using add_routes which exists for reasons I won't go into here because it's a long tangent. Necessary evil for this kind of work, though.
The isolate_namespace method within Core::Engine scopes everything to the spree namespace. If you're inside a controller that's been drawn underneath the Spree::Core::Engine routes and you want to reference a route for another controller also drawn under that route then you can leave off the spree. prefix on the routing helper.
If you're routing to a different engine, then you will need to have the prefix: main_app. or whatever.
The Engines Guide explains this in greater detail, and I'd recommend reading that.

Recursively redirecting in Rails 3 Routes

We are updating our large web app and getting rid of our URL synonym system. For example, though we only use one model for 'advertiser', it is aliased to 'merchants' and 'sellers', using synonymous paths. Thus, /merchant/1 and /seller/1 use the same exact controller and action as advertiser/1.
We no longer need this functionality, but we do need for old URLs to correctly redirect users to the proper place (i.e. proper controller actions).
So far, I've tried:
1) reading http://guides.rubyonrails.org/routing.html - This lead me to try the following suggestions
2) match '/merchants' => redirect('/advertisers') - this didn't seem to work at all, though the syntax seems correct.
3) iterating over resources (this produces a TON of routes and may cause insecurities):
ADVERTISER_SYNONOYMS = ['affiliates', 'sellers']
ADVERTISER_SYNONYMS.each do |a|
resources :advertisers, :path => a, :as => :advertiser
resources :other_controller do
member do
get :test
match :generate_test
end
end
end
end
We use nested resources in our routes.rb, so I'm struggling with getting these synonymns to be recognized all throughout more complex URLs. If anyone dealt with this problem or has a more elegant suggestion, I'd be most grateful.
There are many ways to handle this, including additional routes in routes.rb like you've tried, or rewrites at the webserver level such as Apache or Nginx.
One solution I like is the rack-rewrite gem; it keeps routes clean and the rules are plain ruby. It provides a set of methods for configuring rewrites and redirects. For your situation, I would want to use permanent redirects. Though I haven't tested it out myself, something like the following may work for you:
# Gemfile
gem 'rack-rewrite'
# application.rb
config.middleware.use(Rack::Rewrite) do
r301 %r{/merchant|seller/(\w+)}, '/advertiser/$1'
end

Using Ruby on Rails link_to to link to controller action

I'd just started toying around with Ruby on Rails and had come across an issue with linking to another action in a controller from a particular view. I am almost certain it's an issue (or lack of code) in my routes.rb file, but I think I'm misunderstanding exactly how this file works & what I have to do. I've got a solution but pretty sure it's not the "best way" to do it.
I have one controller called home with two actions, index (which is the default) and newbill. Inside index.html.erb I have:
<h1>Home View</h1>
<%= link_to "new", :controller => "home", :action => "newbill" %>
However I was getting a routing error:
No route matches {:controller=>"home", :action=>"newbill"}
Doing rake routes gives me the following:
root / {:controller=>"home", :action=>"index"}
I then (following some Googling) added this code to routes.rb
match 'home/newbill' => 'home#newbill', :as => :newbill
And then in my index.html.erb I've got this:
<%= link_to "Name", newbill_path %>
And now this works as expected. My questions however are:
Why does this work? What exactly is going on behind the scenes?
Surely this is not the best way to do it? Adding another match 'home/newbill'... for every controller / action I want to link to seems a rubbish way of doing things.
I really like Ruby, but struggling a bit with this aspect of Rails...routing in general is messing up my head a bit I think!
Any help is much appreciated :D
Thanks,
Jack
I guess the first time your code didn't work because your home controller is defined as a resource.
If you define a controller as a resource in routes.rb file it will support only 7 standard methods (according to REST architecture):
index
new
create
show
edit
update
destroy
If you need any more custom routes you should add them manually, say in your case 'newbill', may go as:
resources :home do
collection do
get :newbill
end
end
But as per my understanding, your newbill method should go to bills controllers new, method not in the home controller.
You are right, Rails routes are little bit confusing (at least for me), but once you understand you can do lots of cool stuff.
Read here for the Rails official routes documentation:
http://guides.rubyonrails.org/routing.html.
You should check out the Rails Routing guide. A read through will help you understand what is going on behind the scenes.
This works becuase rails filters every request through the router looking for a match. This enables you to define custom routes such as domain.com/post when the path is actually blog#post. Prior to rails 3, a catch-all route was the last route in the routes file. This allowed you to define a controller and action and it would just work. I'm on my iPad and not near any projects, so I can't verify it, but I think that route is still there in rails 3.1, it just needs to be umcommented.

Namespaced routes in rails 1

I'm working with some legacy code with the last version of rails 1. Upgrading to a later version of rails isn't possible and as such map.namespace is a private method in this version, otherwise I'd be using it.
I have several resources which I have nested into a submenu for simplicity. Their controllers are all within the folder of that submenu and all inherit that controller's namespace.
I'm having major issues with the sub elements. I have mapped the resources and applied a prefix to them in the form of
map.resources :subitem, :path_prefix => "/sub_menu"
but I'm having major issues with using RESTFul methods on these nested objects. The paths that I'm trying to use, say to delete an object simply do not work.
I'm refactoring this current code base so there's very little I can do, and there's very little I can find on rails 1 routes online. It's a bit of a finicky issue but maybe I've missed something simple about routes.
Do I simply need to manually write out every particular route I can use and then manually prefix it, or is there a simpler way?
My other routes work fine, I simply cannot use the
subitem_path(subitem) :method => :delete
function in my link to
So I figured out how to layout the routes appropriately so I could access the paths
Add to the above route the specified controller you're using and the routes will map accordingly
map.resources :subitem, :path_prefix => "/sub_menu, :controller => "submenu/subitem"
Thanks!

New to Rails. Doubt in Big URL Routing

I have just started learning ruby on rails. I have a doubt wrt routing.
Default Routing in Rails is :controller/:action/:id
It works really fine for the example lets say example.com/publisher/author/book_name
Could you tell me how do you work with something very big like this site
http://www.telegraph.co.uk/sport/football/leagues/premierleague/chelsea/
Could you let me understand about the various controllers, actions, ids for the above mentioned url and how to code controller, models so as to achieve this.
Could you suggest me some good tutorials when dealing with this big urls.
Looking forward for your help
Thanks in advance
Gautam
This is achieved using nested resources (read or google for "rails restful routes". In your case it could look something like this:
map.resources :sports do |sport|
sport.resources :leagues do |league|
league.resources :team
# probably more nested routes for members or sponsors or whatever...
end
end
end
You can also view your defined routes with rake task:
$ rake routes
This RailsCasts episode also covers some basics on restful routing with nested resources.
The routing engine can handle URLs of arbitrary size. It all depends on what your spec is. For that it would be:
map.sport_league_team '/sport/:sport/leagues/:league/:team'
What controller you route that to is the important part. This is then called like:
<%= link_to("Chelsea", sport_league_team_path('football', 'premierleague', 'chelsea') %>
You can always examine what routes are defined with:
rake routes
The Rails Routing from the Outside In guide is a good place to start.

Resources