0

I have a Post model that

has_many photos 

The Post model has

accepts_nested_attributes_for :photos

In my Post edit form i show all the images that are currently associated with the post

<% for photo in @post.photos %>
  <%= image_tag(photo.avatar.url(:thumb)) %> <%= link_to "Remove Photo", post_photo_path(@post, photo), :method => :delete %>
<% end %>

When hovering over over the Remove Photo link the path looks like so

http://localhost:3000/posts/17/photos/45

I get uninitialized constant PhotosController, but that's expected as there isn't one.

My question is do i create one and have a destroy action in there that will just delete that photo.. Is this the way to go about it or is there a better way?

EDIT

Photos Controller

 def destroy
  @photo = Photo.find(params[:id])
  @photo.destroy
  redirect_to edit_post_path, :notice => "Successfully deleted Photo"
 end

Routes

resources :posts do
resources :photos
resources :departments
end

Rake Routes

edit_post GET    /posts/:id/edit(.:format)

Thanks

2 Answers 2

3

The option you described, invoking the destroy action of a PhotosController, would certainly do the trick and would probably be the simpler and quicker solution. Be careful that if a user makes changes to other aspects of the Post and then clicks a link to delete the Photo in the same form, their changes would probably get lost. However, using AJAX might help alleviate this concern.

Another option would be to leverage rails existing support for nested forms. Because you are already using a nested form with accepts_nested_attributes_for you're about halfway there. If you haven't seen this yet, check out Ryan Bates' podcast on Nested Forms:

http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2

And if you're willing to pay (trust me, it's worth it), the revised solution is a little nicer:
http://railscasts.com/episodes/196-nested-model-form-revised

The meat and potatoes of what you're interested in is towards the middle to the end of the podcast where Ryan uses the hidden _destroy field in the nested element's params to indicate to the controller than when the parent object is updated, the nested association should be destroyed.

You can also find an off the shelf gem that wraps up this same Rails/Javascript functionality that Ryan implemented from scratch. I've used cocoon in the past and have been quite pleased.

This technique is a little more complicated but I tend to prefer it in this case because the focus of the form is to modify a Post, not a Photo. In the first solution, you would have to make the PhotosController#destroy action redirect back to the form. Or if you use AJAX, then you would have to write javascript that was tailored to the layout of your Post HTML to properly hide/remove the element after it was destroyed. This may be ok for small applications, but as the project grows you may find yourself trying to use the same PhotosController for other work-flows and that could become brittle to maintain.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @Keith that is a very helpful answer, something which i shall definitely look into, getting back to the edit form after delete is proving to be an issue, the route is edit_post_path but i get cant find Post with ID error
1

My opinion is that the best thing to do would be to create a PhotosController to handle the destroy action. That way you will preserve the Single Responsibility Principle, and have less workaround with adding custom routes.

Also, there is the option to put that one action in the PostsController if you are really sure you won't be adding any additional actions connected to Photos (like tagging photos, or whatever).

It's really up to you, but i believe the first one is easier.

If your going with the second option, be sure to create a route for the destroy photo action in the PostsController and the link should be pointing at that exact action.

Your routes.rb:

resources :posts do
   resources :photos, :only => [:destroy]
   resources :departments
end

18 Comments

thanks, ive added my Photos Controller Destroy method, just your regular destroy action?
yes, and don't forget to add it in the routes like: resources :photos, :only => [:destroy]
thanks, ive added my routes, do i still add the :only => [:destroy] to photos?
thanks, so this only allows me to invoke the destroy method in my photos controller? and safeguards against any other actions being carried out?
yes. If you will want to add extra actions, just change your routes.rb
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.