Passing a delete method with params - ruby-on-rails

<% #books.each do |book| %>
<% unless book.checkout_user_id == nil %>
<%= link_to "delete checkout", book_checkout_path(book_id: book.id), :confirm => 'Are you sure?', :class => "button", :method => :delete %>
<% end %>
<% end %>
In the above code, I want to pass a parameter to my book_checkout controller. How can I make it so my destroy method will retrieve the :book_id passed in from book_checkout_path.
Then create an instance to search for a checkout with the corresponding book_id attribute rather than search by ID.
def destroy
#book_checkout = BookCheckout.where(book_id: book_id).first # this line is wrong
#book_checkout.destroy
redirect_to books_path
end
EDIT: Added routes.
routes:
book_checkout GET /book_checkouts/:id(.:format) book_checkouts#show
PATCH /book_checkouts/:id(.:format) book_checkouts#update
PUT /book_checkouts/:id(.:format) book_checkouts#update
DELETE /book_checkouts/:id(.:format) book_checkouts#destroy

I had to fix my original code for a workaround, but it isn't the cleanest.
<%= link_to "delete checkout", book_checkout_path(id: book.id, check: book.id), :confirm => 'Are you sure?', :class => "button", :method => :delete %>
My original link_to NEEDS to pass id because my routes expect that, so I added a check which passes the attribute i will need.
#book_checkout = BookCheckout.find_by(book_id: params[:check])
In my checkout controller, I used the params[:check] instead of params[:id], because I cannot overwrite params[:id] with the book.id.

#book_checkout = BookCheckout.find_by(book_id: params[:book_id])
Since the route only has one id, I think you can use
book_checkout_path(book.id)
However, it seems strange to use the Book id to find the BookCheckout. Is there any special reason you can't do:
book_checkout_path(book_checkout.id)
and
#book_checkout = BookCheckout.find_by(id: params[:id])
Also, is it possible that both the Book id and the Book Checkout id are the same (1)? This would make it appear to succeed when it shouldn't.

Related

How do you recreate a remote link with the same .js update in Ruby on Rails?

Basically I want to make a link able to be refreshed dynamically from "Favorited" to "Removed", and at the same time give the user the option to go go back by reclicking the new button. The action does happen though, because when I refresh the page the updated button shows. Why does clicking the "Favorite this Classroom" link not work? The "Remove this Classroom" link seems to work. Thanks for your help
favorites_controller.rb:
def create
current_classroom.add_to_favorites(#classroom)
current_classroom.save
respond_to do |format|
format.js { }
format.html {redirect_to #classroom}
end
end
def destroy
current_classroom.remove_from_favorites(#classroom)
current_classroom.save
respond_to do |format|
format.js { }
format.html {redirect_to #classroom}
end
end
favorites/create.js.erb
$("#favorite_classroom").html("<%= escape_javascript(link_to 'Remove the Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete) %>");
classrooms/_classroom_details.html.erb
<div id="favorite_classroom">
<% if loggedin_user.favorite_classroom?(#classroom) %>
<%= link_to 'Remove this Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete %>
<% else %>
<%= link_to 'Favorite this Classroom', classroom_favorites_path(#classroom), :remote => true, :method => :post %>
<% end %>
routes:
classroom_favorites POST /classrooms/:classroom_id/favorites(.:format) {:action=>"create", :controller=>"favorites"}
classroom_favorite DELETE /classrooms/:classroom_id/favorites/:id(.:format) {:action=>"destroy", :controller=>"favorites"}
Error when I click on the "Favorite this Classroom" link:
ActionView::Template::Error (No route matches {:action=>"destroy", :controller=>"favorites"
Thanks!
You are using double-quotes twice in your js file. You can't do that. You need to rewrite it like this -
$("#favorite_classroom").html("<%= escape_javascript(link_to 'Remove the Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete) %>");
Notice now that Remove the Classroom is enclosed in single quotes rather than double.
In addition, your route is incorrect because you have nested favorites within classrooms. When you write the link, you need to add the #favorite object that you are trying to delete:
= link_to 'Remove Favorite', classroom_favorite_path([#classroom, #favorite]), :remote => true, :method => :delete
Now the route you are trying to access is valid. That should get rid of the error.
I don't think you need the favorite controller, what you need is favorite/unfavorite action for classroom controller. Here's how it might look
classroom_controller.rb
respond_to :html, :js
def favorite
# ... find classroom by id
# do your stuff
#classroom.favorite = !#classroom.favorite
respond_with(#classroom)
end
views/classrooms/favorite.js.erb
<%# the message should be oposite to favorite %>
<% msg = #classroom.favorite ? "Remove this Classroom" : "Favorite this Classroom" %>
$("#favorite_classroom").html("<%= escape_javascript(link_to msg, [:favorite, #classroom], :remote => true) %>");
Here's the trick with path helper, [:favorite, #classroom] should be transleted to /classrooms/:id/favorite. If it won't work then try favorite_classrooms_path(#classroom)
And finally add to your routes.rb
resource :classrooms do
member { get :favorite }
end
Looks like you need to reference 'favorite_id' in your link to match your routes.
In your case, would probably be:
classroom_favorite_path([current_classroom, #classroom])

Deleting from a namespace

I have setup a admin namespace in order to access models in the admin area: /admin/pages
However i have the following problem
i cant get the delete function to work under Admin::PageController for example or any of my models.
Does anyone know how to do this.
I have the following:
Admin::PageController I have the following
def destroy
#page = Page.find(params[:id])
#page.destroy
respond_to do |format|
format.html { redirect_to admin_pages_url }
format.json { head :ok }
end
end
Then on my page index file where i want a link to delete the record i have the following: (/admin/pages)
<%=link_to admin_page_path(page), :class => 'ico del' do %>
<%='Delete'%>
<% end %>
Does not seem to work. Anyone know how to get this to work?
you have missed :method option in link_to call
link_to 'Delete', admin_page_path, :confirm => 'Are you sure?', :method => :delete
or
<%=link_to admin_page_path(page), :class => 'ico del',:method => :delete do %>
<%='Delete'%>
<% end %>
The link_to helper defaults to a GET request unless you specify additional attributes to tell it how you want it to be handled.
In this case, you need to set some extra arguments:
<%=link_to "Delete", admin_page_path(page), :class => "ico del", :remote => true, :method => :delete %>
What actually happens in the background is the Rails UJS (unobtrusive javascript adapter) captures the click event and sends the request via AJAX. So you should see it hit your server with a POST (but it passes in _method => delete as well) to delete the object.
I'm also assuming you have your routes set up correctly. Something like:
namespace :admin do
resources :pages
end

Using a checkbox to delete an object in rails?

I've got the following form:
<%= form_for(#subscription = #task.subscriptions.build(:user_id => subscribers.id)) do |f| %>
<%= f.check_box :subscribed, :class => 'submittable' %>
<%= f.label :subscribed, subscribers.full_name %>
<%= f.hidden_field :user_id, :value => subscribers.id %>
<%= f.hidden_field :task_id, :value => #task.id %>
<% end %>
The 'submittable' class on the checkbox causes the form to be submitted (via jQuery) on update.
:susbcribed is returned via a method in model that returns whether a user is subscribed or not - it cannot be modified directly.
The controller is available here: http://pastebin.com/zZy6KcXz - it is the standard scaffold.
When I click the checkbox, the subcription is successfully created, but I cannot work out how to get it to delete the subscription when unticked.
cjm, in follow up to jimworm's answer, the controller's destroy method is called when you DELETE (HTTP verb, it's actually a POST with a _method=DELETE field passed since some browsers don't support the DELETE verb.
as he said:
<%= link_to 'Delete', #model, :confirm=> 'Are you sure?', :method=> :delete %>
The route is the same as your show or GET /models/1 but the verb DELETE is used instead,
DELETE /models/1
which is actually
POST /models/1 with a hidden field _method=DELETE passed in order to support all browsers.
As he also mentioned, Rails automatically figures out which action to use when using form_for by checking to see if the #model is a new_record? (no id yet) or an existing one. It will then pick
POST /models for create
or
PUT /models/1 for update
It's a form_for #subscription, so it'll probably be submitting to the create or update actions, which don't destroy models. You could hack the action or the model to make it destroy on create(!)/update. Probably the action... updating the model for this hack gives me the heeby-jeebies.
The Rails way™ to the DELETE method and get to the destroy route is a link like this:
<%= link_to 'Delete', #model, :confirm=> 'Are you sure?', :method=> :delete %>
Watch out for IE9 though. If you let your redirects go to another "deleteable" it'll potentially go up the chain and delete your entire database. http://techno-weenie.net/2011/8/19/ie9-deletes-stuff/
The correct redirect after successful POST, PUT and DELETE is:
redirect_to path, :status => 303

ROR ways of calling destroy action

I ask this question only because I'm curious.
The first line is standard, RESTful and of course invokes destroy method.
The second line returns a routing error.
The question is how to repair the second line to work like the first one. As I mentioned before, It's just for my curiosity and better ROR understanding.
<%= link_to 'delete', file, :method => :delete %></td>
<%= link_to 'delete', {:action => :destroy, :controller => 'files', :id => file.id.to_s}, :method => :delete %>
Bye
Disclaimer: I know this is not the way to do a delete. It is proof of concept on just how to access an action via a controller outside of REST.
You can do this:
<%= link_to 'delete', {:action => :destroy, :controller => 'files', :id => file.id} %>
You don't need the method destroy if you explicitly access the action. Also don't need the to_s for the file.id

Associated models in Rails?

In my rails application I have two models called Kases and Notes. They work in the same way comments do with blog posts, I.e. each Kase entry can have multiple notes attached to it.
I have got everything working, but for some reason I cannot get the destroy link to work for the Notes. I think I am overlooking something that is different with associated models to standard models.
Notes Controller
class NotesController < ApplicationController
# POST /notes
# POST /notes.xml
def create
#kase = Kase.find(params[:kase_id])
#note = #kase.notes.create!(params[:note])
respond_to do |format|
format.html { redirect_to #kase }
format.js
end
end
end
Kase Model
class Kase < ActiveRecord::Base
validates_presence_of :jobno
has_many :notes
Note Model
class Note < ActiveRecord::Base
belongs_to :kase
end
In the Kase show view I call a partial within /notes called _notes.html.erb:
Kase Show View
<div id="notes">
<h2>Notes</h2>
<%= render :partial => #kase.notes %>
<% form_for [#kase, Note.new] do |f| %>
<p>
<h3>Add a new note</h3>
<%= f.text_field :body %><%= f.submit "Add Note" %>
</p>
<% end %>
</div>
/notes/_note.html.erb
<% div_for note do %>
<div id="sub-notes">
<p>
<%= h(note.body) %><br />
<span style="font-size:smaller">Created <%= time_ago_in_words(note.created_at) %> ago on <%= note.created_at %></span>
</p>
<%= link_to "Remove Note", kase_path(#kase), :confirm => 'Are you sure?', :method => :delete, :class => 'important' %>
</div>
<% end %>
As you can see, I have a Remove Note destroy link, but that destroys the entire Kase the note is associated with. How do I make the destroy link remove only the note?
<%= link_to "Remove Note", kase_path(#kase), :confirm => 'Are you sure?', :method => :delete, :class => 'important' %>
Any help would, as always, be greatly appreciated!
Thanks,
Danny
<%= link_to "Remove Note", note_path(note), :confirm => 'Are you sure?', :method => :delete, :class => 'important' %>
you also will need the following entry in config/routes.rb (check if it already exists)
map.resources :notes
and check for following method in your NotesController
def destroy
#note = Note.find(params[:id])
#note.destroy
.... # some other code here
end
there's also another way of doing that if you don't have a NotesController and don't want to have it
You're calling the delete method on a kase -t hat's why it's deleting a kase. There's nothing in this link
<%= link_to "Remove Note", kase_path(#kase), :confirm => 'Are you sure?', :method => :delete, :class => 'important' %>
apart from the text that even mentions a note - so why would it delete a note? Try
<%= link_to "Remove Note", note_path(note), :confirm => 'Are you sure?', :method => :delete, :class => 'important' %>
This assumes you have the standard restful routes and actions set up.
As an additional point, you should never use link_to for non-get actions, because
google spiders and the like will
click on them. You might say 'they
can't because you need to be logged
in' and that's true but it's still
not a good idea.
if someone tries
to open the link in a new tab/window
it will break your site, or go to
the wrong page, since it will try to
open that url but with a get instead
of a delete.
generally, in web
design, links should take you
somewhere and buttons should 'do
stuff', ie make changes. A
destructive action like this
therefore belongs on a button not a
link.
Use button_to instead, which constructs a form to do that same thing.
http://railsbrain.com/api/rails-2.3.2/doc/index.html?a=M002420&name=button_to

Resources