kaigth
kaigth

Reputation: 158

Rails 3 Finding the right :id in a controller using a specific route

I have my routes arranged so that when visiting the site the :id is displayed before the slug like so

match "/causes/:id/:slug" => "causes#show", :as => :cause, :via => 'get'

But I also have a nested attribute called "post" that belongs to causes like so

match "/causes/:id/:slug/posts" => "causes#posts", :via => 'get', :as => :posts

When I use this, everything works great for the causes, but not for the posts.

If I use

@post = Post.find(params[:id])

in causes or posts controller it always looks for the ID of the causes, and not the :id of the posts. So if the post :id is 9, and the cause :id is 1, and I use

@post = Post.find(params[:id]) 

it will always look for post[1] and not 9 or whatever the post id really is.

What am I doing wrong? Is there a way to make this work in the routes, or maybe a different way to find the id of a nested object in the controller?

I need the route to be the way I have it set up, :id/:slug...

rake routes information:

                 cause GET        /causes/:id/:slug(.:format)            causes#show
            edit_cause GET        /causes/:id/:slug/edit(.:format)       causes#edit
                       PUT        /causes/:id/:slug(.:format)            causes#update
                 posts GET        /causes/:id/:slug/posts(.:format)      causes#posts
                       POST       /causes/:id/:slug/posts(.:format)           
                       PUT        /causes/:id/:slug/posts(.:format)  causes#update_post
                       DELETE     /causes/:id/:slug/posts(.:format)  causes#destroy_post
                causes GET        /causes(.:format)                      causes#index
                       POST       /causes(.:format)                      causes#create

Any help would be great.

Upvotes: 1

Views: 221

Answers (2)

MatthewFord
MatthewFord

Reputation: 2926

This is because you're using the id of the cause, and if you're doing /causes/:id/posts shouldn't you be doing @posts = @cause.postsanyway?

I would look into the new router syntax for rails 3 if I were you, as there is a nicer way to nest resources http://guides.rubyonrails.org/routing.html


edit: use the friendly_id gem and nest your resources, to avoid confusion follow REST best practises that resource in question is at the end so

/causes/:slug/posts/:slug

Upvotes: 1

declan
declan

Reputation: 5635

To solve your immediate problem, you'll want to add something like this to routes.rb

# config/routes.rb
match "/causes/:cause_id/:slug/post/:id" => "causes#update_post", :via => 'put', :as => :update_post

And then you can generate the URL in your views like this...

link_to 'Update this post', update_post_path(@cause, @post)

...and access the parameters in your controller as params[:id] (for the post) and params[:cause_id] (for the cause).

More generally, though, the way you are specifying your routes is pretty cumbersome, and I suspect you're making your life harder than it needs to be. If this were me, I would do something like

# config/routes.rb
resources :causes do
  resources :posts
end

This would accomplish something pretty close to what you have now, the main difference being that it wouldn't contain slugs. I'm not sure why you need to have both slugs and IDs, maybe you could just identify your causes by their slugs? Stringex is a good gem for generating slugs, and you can set it so that slugs are guaranteed to be unique.

Here is the section of the Rails guide on nested resources http://guides.rubyonrails.org/routing.html#nested-resources

And here is a Railscast about using slugs with nested resources http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=comments

Hope this helps.

Upvotes: 1

Related Questions