How can I call different controllers from routes.rb - ruby-on-rails-3

I'm just struggling a few hours with a problem, that seems rather easy, but not for me and not for google :)
I put some routes via
scope :path => '/:mandate_key', :controller => :tasks do
get '/' => :index #mandate_path
match '/import' => "import#index"
match '/clearance' => "clearance#index"
end
So far, so ugly! I'm looking for a way to call different controllers (import and clearance) dependent on the second param. Something like this:
scope :path => '/:mandate_key', :controller => :tasks do
get '/' => :index
scope :path => ':task_key', :controller => %{'task_key'}
get '/' => :index
end
end
where :task_key should be recognized as params[:task_key] and the called controller should be the value of params[:task_key]
So if a click a link like http://some.url/a_mandate_key/import it should call the ImportController.
I'm sure that the solution will be simple, but finding is hard!

Sometimes one is looking for a highly complicated solution, but it could be so much easier:
scope :path => '/:mandate_key' do
get '/' => "tasks#index" #mandate_path
get '/import' => "import#index"
get '/clearance' => "clearance#index"
end
Calling http://localhost/mandate the controller 'mandate' is called an params[:mandate_key] provides 'mandate'
Calling http://localhost/mandate/import the controller 'import' is called an params[:controller] provides 'import'
Trying the easy way is often the best way :)
Thanks for your help, Bohdan!

you might add in the bottom of your routes match ':controller(/:action(/:id))' so any unknown url will be dispatched this way
How about
scope :path => '/:mandate_key', :controller => :tasks do
get '/' => :index #mandate_path
end
....
match ':mandate_key/:controller(/:action)'
first scope will match routes /:mandate_key/tasks and the second one /:mandate_key/:controller or /:mandate_key/:controller/:action however second part should be defined in the bottom of your routes.rb file otherwise it'll match wrong routes

Related

Rails simulate nested resources with basic views from same controller

If in views/abouts/ I have "index.html.haml" and "history.html.haml".
How can I access to abouts#history which is a basic html page.
From log I get this error, I guess it is processing it as a show, what can I do?:
Processing by AboutsController#show as HTML
Parameters: {"id"=>"history"}
About Load (0.3ms) SELECT `abouts`.* FROM `abouts` WHERE (`abouts`.`id` = 0) LIMIT 1
ActiveRecord::RecordNotFound (Couldn't find About with ID=history):
routes.rb
scope() do
resources :abouts, :path => 'about-us' do
match 'about-us/history' => "about-us#history"
end
end
abouts_controller.rb
def history
respond_to do |format|
format.html
end
end
A few problems. First, you should be matching 'history' and not 'about-us/history' (the route is nested so the 'about-us/' part is automatically included). Second, you need to specify that the route should match the collection, not a member of the collection, with the :on => :collection option. Finally, you should be routing the match to 'abouts#history' and not 'about-us#history' (because the controller is named abouts regardless of what path string you use when routing).
So try this:
resources :abouts, :path => 'about-us' do
match 'history' => "abouts#history", :on => :collection
end
Also note that match will match all HTTP requests: POST as well as GET. I'd suggest using get rather than match, to narrow the HTTP request type to just GET requests:
resources :abouts, :path => 'about-us' do
get 'history' => "abouts#history", :on => :collection
end
Hope that helps.

Using generated paths with resources in Rails

I have following routes defined:
CyberTrackRails3::Application.routes.draw do
scope "(:locale)", :locale => /en|de|nl/ do
resources :login do
get 'index', on: :collection
get 'check', on: :collection
end
end
end
Now, url_for(:controller => 'login', :action => 'check'), gives me the correct url, en/login/check.
Using login_check_path however doesn't work. How do I make this work?
I've tried replacing get 'index', on: :collection with match 'check' => 'check' but that doesn't work. Neither does match 'check' => 'login#check'.
since you're adding an action to a resource, i think the automatically generated name is going to be reversed, ie 'check_logins_path' (see adding-more-restful-actions)
do you need login_check_path specifically? if so, you should be able to define the path outside of the resources :login block, ie
match '/login/check' => 'login#check', :via => :get, :as => 'login_check'
and like Fivell suggested, rake routes will show you the automatically generated name for a route.

Routes problem with I18n_routing gem

I'm on Rails 3 and on my 2nd Rails project (i.e. I'm a newbie). I am making a website with several locales, at the moment Swedish and US. I am using the I18n_routing gem to create localized url:s. I am also using the friendly_id gem to create better urls.
My problem: I cannot get my nested urls to be translated. They remain as the default-urls.
This is my routes.rb:
localized(I18n.available_locales, :verbose => true) do
resources :calculation_types, :only => [:show], :path => '' do
resources :calculations, :only => [:index, :show], :path => '' do
member do
put 'calculate_it'
get 'calculate_it', :redirect_me => true
get 'link'
end
end
end
end
localized(I18n.available_locales, :verbose => true) do
match 'searchresults' => 'home#search-results', :as => :searchresults
match 'about' => 'home#about', :as => :about
match 'advertise' => 'home#advertise', :as => :advertise
match 'terms' => 'home#terms', :as => :terms
match 'calculator' => 'home#calculator', :as => :calculator
match 'feedback' => 'home#feedback', :as => :feedback
end
This is a sample (cut) of my locale (for Swedish):
se:
named_routes_path:
about: 'om'
advertise: 'annonsera'
calculator: 'kalkylator'
feedback: 'feedback'
searchresults: 'sokresultat'
terms: 'anvandaranvisning'
resources:
accumulated-passive-income: "vardet-av-din-passiva-inkomst"
all-about-a-date: "allt-om-ett-datum"
area: "area"
average-speed: "genomsnittshastighet"
birthday-in-days: "fodelsedag-i-dagar"
These are some facts of the case:
The resources-translations include both "calculation_types" and "calculations".
I have tried several set-ups in the translation file.
The SECOND routing WORKS, the one with the "match", they also appear when I do rake routes.
I get no error messages. Everything works fine.
I am using friendly_id as the url-words. An example of a url could be http://local.domain.com:3000/diet/bmi where "diet" is calculation_type.friendly_id and bmi is calculation.friendly_id
I want help with:
- Why do the nested routes not show up as routes? Why are they not being created?
- How do I get this to work?
Do you need any more info to help me?
It seems like it is not a matter of I18n_routing after all since the words that should be translated are actually friendly_id:s. So, disregard the I18n_routing part of this problem and focus on the friendly_id-translation...

Trying to create a POST request but getting No route matches [GET]

I'm trying to do something similar to Railscasts #255 but I'm getting a No Route error:
In Ryan's routes.rb file:
post "versions/:id/revert" => "versions#revert", :as => "revert_version"
In in the controller where he uses the route, versions_controller.rb
link = view_context.link_to(link_name, revert_version_path(#version.next, :redo => !params[:redo]), :method => :post)
redirect_to :back, :notice => "Undid #{#version.event}. #{link}"
In my routes.rb
post "/approve/:id" => "listings#approve", :as => "listing_approve"
and view where I use my link:
<%= link_to 'Approve Content', listing_approve_path(#listing), :method => :post %>
My tests return to me a ActionController::RoutingError: No route matches [GET] "/approve/1"
If I leave the method as a GET everything works.. Using rails 3.1.0rc5. Any guidance as to what I'm doing wrong here would be very much appreciated..
EDIT: routes.rb file (the last line is set as match right now to work)
RLR::Application.routes.draw do
root :to => "home#index"
devise_for :users, :controllers => { :registrations => "registrations" }
devise_for :users
match '/user' => "layouts#index", :as => :user_root
resources :users, :only => :show
resources :layouts, :only => [:index, :show]
resources :listings
resources :features
resources :orders
match "/preview/:id" => "listings#preview", :as => "listing_preview", :via => "get"
match "/approve/:id" => "listings#approve", :as => "listing_approve"
end
Hmmmm, it looks right to my eye. The test sounds like it is generating a GET instead of a POST though, so it might be a problem with the link_to call. You've got :method => :post there, so it should be fine. http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to seems to indicate that link_to will generate some javascript to make a POST call on click (and that users with javascript disabled will get a normal GET link unless you use :href="#"), so it might be because your test engine isn't running the javascript.
You can fix this by changing it to a button that submits a hidden form, but that might not be the visual representation you want.
It might be a precedence thing - the first matching route definition in routes.rb is used, so if you have a resources route or something like that it may be matching on that first.
I got the same problem in my rails application and I solved it the same way you did by doing a via: :get on the match instead of a via: :post. I think for some reason when you send a request in the format of /something/:id it will automatically assume its a [GET] request and search for a get route. This of course will cause problems in your routes if you have it as a :POST.
If anyone has a better solution or idea as to why you cannot send a post request in the format '/something/:id' let me know please.

Better way to route this?

I have a routing issue. my routes currently look like this:
http://localhost:3000/events?category=popular&city=london&country=united-kingdom
Currently its just looking at resources :events (which is the events controller, index action), and in the index action. I've got a lot of if conditions. Especially, when the app needs to determine which partials to load, based on the query strings.
Is there a better way to refactor this? I am not a big fan of query strings in the URL. And something like this can be solved in routing. Just looking for the right direction. Am looking to have urls like:
/events/london
/events/london/popular
/events/london/united-kingdom
/events/united-kingdom
/events/united-kingdom/popular
/events/london/united-kingdom/popular
The Anti Patterns book, specifically on page 181, suggests creating separate controllers. Which will organize the code further and still keep it RESTFUL.
In theory, I think it is suggesting something like this:
match 'events/:city', :controller => 'events/cities', :action => 'index', :as => 'by_city', :via => :get
match 'events/:city/:category', :controller => 'events/cities_and_categories', :action => 'index', :as => 'by_city_and_category', :via => :get
match 'events/:city/:country', :controller => 'events/cities_and_countries', :action => 'index', :as => 'by_city_and_country', :via => :get
match 'events/:country', :controller => 'events/countries', :action => 'index', :as => 'by_country', :via => :get
match 'events/:country/:category', :controller => 'events/countries_and_categories', :action => 'index', :as => 'by_country_and_category', :via => :get
match 'events/:city/:country/:category', :controller => 'events/cities_and_countries_and_categories', :action => 'index', :as => 'by_city_and_country_and_category', :via => :get
OR, are filtered terms REALLY supposed to be in query string format?
If you have a suggestions / better approach. Do mention.
First off, some cleaner routes that are more canonical:
resources :events do
get '/:country(/:city)(/:category)' => 'events#filtered', :on => :collection, :constrain => { :category => %w{ popular legal_marijuana } }
end
I've made the country required. There are too many ambiguous city names, and unless you want to do a lot of poking to determine segment is what, this is just more straightforward. The city is optional, and so is the category.
Unless I've mistaken something here, this will constrain the category to either "popular" or "legal_marijuana" (but not both, so Amsterdam is out, haha).
All of these routes go to a single filtered action on your events controller. Don't bother trying to keep this resourceful unless it makes sense for every country and city to be a resource for your application. As long as this responds to a GET request, and it retrieves a collection of records, it's not very far out of the bounds of the REST principals (interesting note, the new and edit actions in Rails don't adhere strictly to REST either).
This action will need to do a bit of poking at params to see whether or not you have a city or category. You can use something like this to help you out:
#event = Event.where(:country => params[:country])
#event = #event.where(:city => params[:city]) if params[:city]
[For some reason this doesn't look right to me. I can't think straight. I'm sure that this is a mess. Someone please save me.]
But yeah, that's the idea.