Rails simulate nested resources with basic views from same controller - ruby-on-rails-3

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.

Related

Rails 3.1 How do I create an API route for "me" that points to the user resource

I have a set of API routes in rails as follows
namespace "api" do
namespace "v1" do
resources :users do
resources :posts
resources :likes
...
end
end
end
So far, so good. I can GET /api/v1/users/fred_flintstone and retrieve all of the information for that user.
What I would like to do now is add the concept of "me" (ala facebook) such that if the user is authenticated (fred_flintstone), I can also do the following
GET /api/v1/me
GET /api/v1/me/posts
...
I require both sets of routes. So I want to achieve the same results either using GET /api/v1/me/posts OR GET /api/v1/users/fred_flintstone/posts.
I've been through the route tutorial and have googled so a pointer would be as much appreciated as a direct answer.
EDIT:
What I've done that has worked is pretty hacky. I've created a second set of entries in the routes table using a scope:
scope "/api/v1/me", :defaults => {:format => 'json'}, :as => 'me' do
resources :posts, :controller => 'api/v1/users/posts'
resources :likes, :controller => 'api/v1/users/likes'
...
end
And then I added a set_user method that tests for the presence of params[:user_id]. I'm really looking for a way to DRY this up.
What about leaving the routes the way they are in your post, and just solving this inside the controller?
Heres a before_filter that you could apply to all of the routes you have which pull a User from a :user_id.
# Set the #user variable from the current url;
# Either by looking up params[:user_id] or
# by assigning current_user if params[:user_id] = 'me'
def user_from_user_id
if params[:user_id] == 'me' && current_user
#user = current_user
else
#user = User.find_by_user_id params[:user_id]
end
raise ActiveRecord::RecordNotFound unless #user
end
Then in your controller functions you can just use the #user variable without having to worry about whether the user passed a user_id, or me.
Hope that helps! :)
EDIT:
Lemme take another shot, given your comments.
How about a function that lists all the resources you wish to access via both the standard routes and the /me route. Then you can just use the function in both the namespaces you require.
routes.rb
# Resources for users, and for "/me/resource"
def user_resources
resources :posts
resources :likes
...
end
namespace 'api' do
namespace 'v1' do
resources :users do
user_resources
end
end
end
scope '/api/v1/:user_id', :constraints => { :user_id => 'me' },
:defaults => {:format => 'json'}, :as => 'me' do
user_resources
end
# We're still missing the plain "/me" route, for getting
# and updating, so hand code those in
match '/api/v1/:id' => 'users#show', :via => :get,
:constraints => { :id => 'me' }
match '/api/v1/:id' => 'users#update', :via => :put,
:constraints => { :id => 'me' }

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.

rails rspec controller test ActionController::RoutingError

My routes looks like this
resources :stores, :except => [:destroy] do
resources :toys, :member => {:destroy => :delete}
end
my objects controller spec look like this
require 'spec_helper'
describe ToysController do
describe "GET index" do
it "assigns all toys as #toys" do
toy11 = Factory(:toy, :is_shiny => true)
toy12 = Factory(:toy,:is_shiny => false)
get :index
assigns(:toys).should eq([toy12,toy11 ])
end
end
end
end
I got the following error
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"toys"}
Since the toys resource is nested under stores resources its not able to get toys_path route so i think so the spec is failing.
How do i pass the spec?
Thanks
The error is due to not sending store_id to tyos index.
Had i sent
:store_id => #store.id in get :index
it would have passed.

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.