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
Related
<% #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.
If I do scaffold, it automatically makes destroy action in index.html.erb.
What if I want to move this action to _form.html.erb?
And I'd like to make it appear only during edit mode(example.com/books/1212/edit)
not during new mode(example.com/books/new)
I think this would help you
model
class Job < ActiveRecord::Base
attr_accessible :delete_flag #with other attributes
attr_accessor :delete_flag
end
*in your view (_form)*
<%= form_for(#job) do |f| %>
#other code
<%= f.text_field :delete_flag%>
<div class="actions">
<%= f.submit %>
<%= f.submit "Delete",{:class => "delete_button"} %>
</div>
<% end %>
coffeescript
jQuery ->
$('#new_job').submit ->
#capture your delete button click
$('#job_delete_flag').val("1")
in your controller you will get params as :delete_flag, and from there you could
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5oWQU+w0jVCQlw8wLvCyKajbBSKpK2sv6RMkSGTE2H8=", "job"=>{"delete_flag"=>"1"}, "commit"=>"Delete"}
HTH
This is possible, but make sure when you click on the delete button it does not file the form submit action.
You might consider using :remote => true for delete link and you could check if the record is new or existing by using:
<Object>.new_record?
Ex: if I have a model called Job
Job.first.new_record? #=> false
Job.new.new_record? #=> true
Ex: something like (not tested :D, just to give you an idea)
<%= form_for(#job) do |f| %>
#your form content
<%= f.submit %>
<%= (link_to 'Destroy', #job, :remote => true, method: :delete, data: { confirm: 'Are you sure?' }) unless #job.new_record? %>
<% end %>
Can't seem to get my delete method to work on a micropost, heres the code:
Code for delete link:
<%= link_to "delete", micropost, :class => "delete_link",
:method => :delete,
:confirm => "You sure?",
:title => micropost.content %>
The micropost controller:
def destroy
#micropost.destroy
redirect_back_or root_path
end
end
Any ideas?
Rails 3.1 uses unobtrusive javascript now. Now the javascript has been moved out of the link, and into external js files. Make sure you have this in your layout:
layout/application.html.erb
<%= javascript_include_tag :all %>
or
If you use ':defaults' like following, in layout/application.html.erb
<%= javascript_include_tag :defaults %>
Then you should specify following in application.rb
config.action_view.javascript_expansions[:defaults] = %w(jquery.min jquery_ujs)
I have a photo gallery that has a Gallery model and an Asset model. See below:
class Gallery < ActiveRecord::Base
attr_accessible :gallery_name, :description, :assets_attributes
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
def find_featured_image
assets.featured
end
def find_only_featured
assets.only_featured
end
class Asset < ActiveRecord::Base
belongs_to :gallery
has_attached_file :image,
:styles => {
:thumb => '150x150#',
:medium => '300x300>',
:large => '600x600>'
}
def self.featured
where( :featured => true ).limit(1)
end
scope :only_featured, where(:featured => true)
end
end
I am able to destroy the assets through my Gallery form, but when I try to destroy the Gallery itself, I am simply redirected to the Show view with no confirmation notice.
Here is my form:
<div id="gallery">
<div class="headers"><h1>MDN Photo Gallery</h1></div></br>
<% #galleries.each do |gallery| %>
<div id="gallery_wrap">
<div id="gallery_left">
<div id="gallery_head"><h2><%= gallery.gallery_name %></h2></div>
<div id="gallery_desc"><%= gallery.description %></div>
</div>
<div id="gallery_rt">
<div id="gallery_featured">
<% for asset in gallery.assets.featured %>
<%= link_to( image_tag(asset.image.url(:medium)), asset.image.url(:large), :class => "fancybox", :rel => gallery.id ) %>
<% end %>
</div>
<div id="gallery_photos">
<% for asset in gallery.assets %>
<%= link_to( image_tag(asset.image.url(:thumb)), asset.image.url(:large), :class => "fancybox", :rel => gallery.id ) %>
<% end %>
</div>
<td><%= link_to 'Show', gallery %></td>
<td><%= link_to 'Edit', edit_gallery_path(gallery) %></td>
<td><%= link_to 'Destroy', gallery, :confirm => 'Are you sure?', :method => :delete %></td>
</div>
</div>
</br>
<% end %>
<br />
<%= link_to 'New Gallery', new_gallery_path %>
</div>
I'm using the standard destroy method that gets created with scaffold:
def destroy
#gallery = Gallery.find(params[:id])
#gallery.destroy
respond_to do |format|
format.html { redirect_to(galleries_url) }
format.xml { head :ok }
end
Is there some change I need to make to the model? the destroy method? anything else? in order to be able to delete the parent of the nested model?
Thanks in advance for your insights.
Any ideas?
It sounds there's something wrong with how the JavaScript support is being loaded. There's no way to have an anchor make a DELETE request directly, so Rails uses JavaScript to respond to the link's click event, and then make the proper request. Without that, the link simply acts as a GET.
I found this discussion on another site that describes exactly the situation I'm faced with:
http://railsforum.com/viewtopic.php?id=38460
The recommendation was made to use the button_to instead of the standard link_to for purposes of security against web bots. I had not heard that before.
Also it was observed that the absence of the <%= csrf_meta_tag %> was found and that the original issue went away and the link_to worked. That is not the case for me.
So now I have a button_for and am able to destroy the record. However, I am not getting the confirmation notice (:confirm). So there is still something wrong, but I can at least deal with the need to delete the record.
I am now able to get the confirmation notification working (:confirm). What I had done was changed javascript_include_tag :defaults to javascript_include_tag :all. I had forgotten I made that change. I'm not sure what is included when the :defaults method is called, but just wanted to let anyone else running into this problem know that is how I fixed it. Sounds like using the Button_to instead of Link_to is still the best solution even though link_to will work now.
I have a rails app with the following code in one of my views:
<% if #present.taken == false %>
<%= link_to "I want to buy this present", :confirm => 'Are you sure you want to buy this present?', :action => "taken_toggle", :id => #present.id %>
<% end %>
However, I don't get a javascript dialog box showing - it just seems to skip that bit (the calling of the action works).
My application layout has the following:
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
So I think I have the necessary javascript loaded.
Any ideas why this isn't working?
As the documentation shows
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
in
Be careful when using the older argument style, as an extra literal hash is needed:
try using like this
<% if #present.taken == false %>
<%= link_to "I want to buy this present", { :action => "taken_toggle"}, :confirm => 'Are you sure you want to buy this present?', :id => #present.id %>
<% end %>