I'm following http://railscasts.com/episodes/250-authentication-from-scratch for simple authentication. It works as expected. I have a model in my app with the following partial :
<%= content_tag_for(:li, post) do %>
<%= link_to 'Delete', post, :confirm => 'Are you sure?', :method => :delete, :remote => true %>
<% end %>
It is called within index.html.erb as follows:
<%= render :partial => #posts.reverse %>
The destroy.js.erb is as follows, which is called if the object is successfully destroyed.
$('#<%= dom_id(#post) %>').css('background', 'red');
$('#<%= dom_id(#post) %>').hide();
On clicking the delete button, the post object gets deleted properly and the destroy.js.erb is rendered correctly too. But somehow, the user is logged out. Following is the code for my posts_controller.rb :
def destroy
logger.error 'in destroy'
#post = Job.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
format.js
end
end
Any clues why this behavior?
And, if I remove the :remote => true from the delete link, then the user remains logged in. I have log statements in the destroy method for session that are never called in either case, but if ':remote=>true then the session is somehow screwed up. On checking the cookies, I found that the cookie is not destroyed but it does get modified when the destroy method on posts is called. Not sure why this has to happen.
Sounds like you are bumping into a rails security feature that is meant to protect against Cross Site Request Forgery. Adding :remote => true causes the request to be submitted via ajax without CSRF security tokens, so rails clobbers the session because it thinks it is a CSRF attack. To get around this you have a few options:
A quick and dirty (and insecure) solution is to turn off the security check for that request. To do this add this line to the top of your controller:
skip_before_filter :verify_authenticity_token, :only => [:destroy]
A more secure solution is to submit the CSRF token with the AJAX call. I think this will happen automatically if you change your remote link to a button_to. Read more here.
<%= button_to 'Delete', post, :confirm => 'Are you sure?', :method => :delete, :remote => true %>
You could also cookies to store the current_user rather than the session. The security implications of this will depend on the details of your app.
Related
Okay so I'm building a really simple list with items app, pretty much exactly the same as your standard to-do list application. I've managed to ajax-ify the creation of new 'points' within a list (point belongs_to :list and list has_many :points) but I'm having trouble with the 'destroy' action.
When I click on the destroy link in the browser, nothing visibly occurs, and I get the error Error: Syntax error, unrecognized expression: /lists/10/points/125 obviously with different values depending on the id of the list and point.
If I refresh the page or look at the db, it's clear that the entry has indeed been deleted. Without ajax, my destroy action works just fine. I feel like I must be missing something obvious, any ideas?
fyi the 'pro' attribute is just a boolean associated with every point.
points_controller.rb
def destroy
#point = #list.points.find(params[:id])
#point.destroy
respond_to do |format|
format.html { redirect_to list_url(#list) }
format.js
end
end
lists/show.html.erb
<% #list.points.each do |point| %>
<% if point.pro == true and point.valid? == true %>
<li class="weight-<%= point.weight %>"><%= point.content %>
<%= link_to "×".html_safe, [#list, point],
:remote => true,
:method => :delete,
:class=> "close",
:data => {:dismiss => 'alert'} %>
</li>
And it doesn't seem to matter what I put in views/points/destroy.js.erb, because the code doesn't seem to be getting executed.
Update
I figured it out, I had to change the path in the delete link to list_point_url(#list, point). The other problem was that my invalid javascript was causing a server error, so I didn't realize what the problem was (turns out #<%= dom_id(#point) %> needed to be wrapped in quotes).
Thanks all!
Maybe check if the delete link routes to the destroy controller action, because list_point_path doesn't really seem like a delete route.
Edit
Sorry for the lake of knowledge but I'm not sure what [#list, point] will produce as a route. This is what I have for a view of my own, just for your reference:
link_to "Delete", admin_photo_path(photo), :method => :delete, :confirm => "Delete this image?", :class => "btn-trash"
My admin_photo_path is a singular path that route to a single Photo instance; not a collection.
Edit
Simple way could be sending delete to the point object, maybe this could help?
link_to "×".html_safe, point,
:remote => true,
:method => :delete,
:class=> "close",
:data => {:dismiss => 'alert'}
I'm having problems with rails 3.2.8 and ajax callbacks... it seems those are not firing at all... I've tried binding with Jquery code (I can see the js script on the chrome toolbox) and I've even tried putting the :success => 'alert("bla")' on the link_to line, but it still doesn't do anything... the controller works since my row is actually deleted... but can't bindd to the callbacks! please help!
Here is my view line:
<td><%= link_to 'Destroy', pet, :method => :delete, :remote=>true, :class => 'delete_pet' %></td>
Here is my controller action
def destroy
#pet = Pet.find(params[:id])
#pet.destroy
respond_to do |format|
format.html { redirect_to(pets_url) }
format.js { render :nothing => true }
end
end
and here is my js code:
jQuery(function($) {
$('.delete_pet').bind("ajax:before", function(){alert('bla2');})
.bind("ajax:success", function(){alert('bla2');})
.bind("ajax:failure", function(){alert('bla2');})
.bind("ajax:complete", function(){alert('bla2');});
});
replace
format.js { render :nothing => true }
with
format.json { render :nothing => true }
and also replace
<%= link_to 'Destroy', pet, :method => :delete, :remote=>true, :class => 'delete_pet' %>
with
<%= link_to 'Destroy', pet, :method => :delete, :remote=>true, 'data-type'=>'json', :class => 'delete_pet' %>
I've been having similar issues with the respond_to blocks. I've gotten around it temporarily by checking the request. For example, you're code would look like:
def destroy
#pet = Pet.find(params[:id])
#pet.destroy
if request.xhr?
# the request was received via an AJAX request
render :nothing => true
else
redirect_to(pets_url)
end
end
Not as elegant as the resond_to block, but it seems to reliably work as expected.
Good luck!
The problem was that on my application.js I was including manually a jquery file... like this..
//= require jquery-ui-1.8.23.custom
shame on me!
I have an otherwise functioning rails project where I'm trying to update some form controls to work over AJAX instead of HTML. But my controller continues to handle it as HTML instead of JS and I'm not sure why.
The link I'm trying to make remote in my users/index.html.erb:
<%= link_to 'Disable', disable_user_path(user), :confirm => 'Are you sure?',
:method => :put, :remote => true %>
Rendered as:
<a href="/users/1/disable" data-confirm="Are you sure?" data-method="put"
data-remote="true" rel="nofollow">Disable</a>
My Users Controller:
def disable
#user = User.find(params[:id])
if #user.update_attribute(:enabled, false)
respond_to do |format|
format.html { redirect_to root_path, :flash => { :success => "Disabled." }}
format.js {}
end
else
redirect_to root_path, :flash => { :error => #user.errors.full_messages }
end
end
My includes in application.html.erb:
<%= javascript_include_tag "//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "//ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js", "jquery.rails.js", "application" %>
I think I pulled down the third and fourth files from a standard place, but if those are possibly the culprit I can look inside them or track down more information about them.
When I test it, it doesn't prompt me with "Are you sure?" and it responds with the redirection and "Disabled" flash message, and the server logs confirm it's being handled as html.
Started GET "/users/1/disable" for 127.0.0.1 at 2012-02-11 17:17:31
-0200 Processing by UsersController#disable as HTML
You may still need to include the unobtrusive javascript adapter if you have not done so already.
It looks like jQuery is not being loaded.
Check your include tag, specifically the resource path...
<%= javascript_include_tag "//ajax.googleapis.com/ajax/libs/....." %>
Most browsers will interpret //... as a local resource, as in local to the browser.
Paste the URL into a browser and see if it will load. I bet it will fallback to the file:// scheme, then complain about not being found (on your local machine).
Either add a http:// scheme on there, or get rid of the double slashes.
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/....." %>
# or...
<%= javascript_include_tag "ajax.googleapis.com/ajax/libs/....." %>
The problem ended up being that my includes weren't grabbing all the files that were apparently needed. I blasted my javascripts directory, installed the gem from scratch per the instructions in the readme, and changed my include to this:
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js", :defaults %>
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
I want to create a method in my rails app that will increase a value tied to a record.
The method in the controller looks like this:
def upvote
#spot = Spot.find(params[:id])
#spot.rating += 1
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #spot }
end
end
Then when viewing the record at "spots/1" I include this code:
<%= link_to 'Upvote', #spot, :confirm => 'Are you sure?', :method => :upvote %>
Which, when clicked, throws the error:
"No route matches "/spots/1""
Even though I'm already at /spots/1. I know this is a routes issue, but I can't seem to give this method a route that works...
The parameter :method identifies the HTTP verb (GET, POST, UPDATE, ...), not the method to be called.
To add a new action, edit the routes.rb file
resources :sposts do
member do
put :upvote
end
end
Then use a named route
<%= link_to 'Upvote', upvote_spot_path(#spot), :confirm => 'Are you sure?', :method => :put %>