Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3 has_one routing

I have two classes:

class User < ActiveRecord::Base
  :has_one :foo
end

class Foo < ActiveRecord::Base
  :belongs_to :user 
end

The Foo is optional.

I created the following routing:

resources :users do
  resources :foo
end

Which results in the following routes:

GET    /users/:user_id/foo(.:format)              {:controller=>"foos", :action=>"index"}
user_foos POST   /users/:user_id/foo(.:format)              {:controller=>"foos", :action=>"create"}
new_user_foo GET    /users/:user_id/foo/new(.:format)          {:controller=>"foos", :action=>"new"}
GET    /users/:user_id/foo/:id(.:format)          {:controller=>"foos", :action=>"show"}
PUT    /users/:user_id/foo/:id(.:format)          {:controller=>"foos", :action=>"update"}
user_foo DELETE /users/:user_id/foo/:id(.:format)          {:controller=>"foos", :action=>"destroy"}
edit_user_foo GET    /users/:user_id/foo/:id/edit(.:format)     {:controller=>"foos", :action=>"edit"}

Questions:

  1. It seems like the Index and Show actions are redundant. Should one of them be removed? If so, which one?
  2. The :id parameter in the Show action seems unnecessary, as user_id is a foreign key in the foos table and there is only one foo per user. Am I mistaken?
  3. I would like to have a graceful way to route to the New action if there isn't a foo. One option would be to test @user.foo.nil? in the FooController's Show or Index action, then redirect to the New action. Is there a better way?

Thanks for your time.

like image 973
craig Avatar asked Jul 27 '10 17:07

craig


People also ask

What is the difference between Has_one and Belongs_to?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

How do I find a specific route in Rails?

Decoding the http request TIP: If you ever want to list all the routes of your application you can use rails routes on your terminal and if you want to list routes of a specific resource, you can use rails routes | grep hotel . This will list all the routes of Hotel.

What is RESTful route in Rails?

In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as. map.resources :photos. creates seven different routes in your application: HTTP verb.


2 Answers

I can understand why Craig missed that actually. It's such a subtle difference it didn't even cross my mind. The only thing that tipped me off is that my named routes for the singleton resource has a weird index name: user_foo_index instead of user_foos.

It's a really smart deduction from the absence of plural on the part of Rails.

Warning: The following examples use shallow nesting by either doing this:

resources :cats, shallow: true do
  resources :noms
end

Or that:

resources :cats do
  shallow do
    resources :noms
  end
end

Anyway back to business, if you setup a singular resource – address as opposed to articles for instance – and you see something like this:

user_address_index GET | POST
  new_user_address GET
      edit_address GET
           address GET | PUT | DELETE

Then as Andreas justly pointed out, you probably incorrectly declared this in your routes:

resources :users do
  resources :address
end

And if you change that to:

resources :users do
  resource :address
end

You should be all fine and happy and see something like this if you punch rake routes in your prompt:

     user_address POST | GET | PUT | DELETE
 new_user_address GET
edit_user_address GET

Note: I know the output of rakes routes doesn't look exactly like this (it's a lot more verbose), I'm just simplifying for the sake of focus.

Hope that helps.

like image 120
Olivier Lacan Avatar answered Oct 12 '22 11:10

Olivier Lacan


If your model has a has_one association, try to set up the route using resource :foo (note the singular method name "resource", not "resources"). This will set up a singleton resource route (which e.g. has no index action and member actions don't have an id param since there's only one member). See also http://apidock.com/rails/ActionController/Resources/resource (2.3 documentation, but applies to 3.0 as well afaik).

like image 29
Zargony Avatar answered Oct 12 '22 10:10

Zargony