简体   繁体   中英

Rails ajax callback after link_to remote

I'm trying to figure out this ajax callback business, and haven't had any luck getting it to work. I've looked at tons of SO questions, tutorials, etc. but am apparently not grasping how this works. I'm trying to update the contents of a div that contains a partial. This is a standard like/unlike type function where the user will click on link and it should update the icon via ajax. My ajax remote requests are working fine, but I can't get the callbacks to work. Here's my show.html.erb file:

<table class="v-table">
    <tr>    
        <td>
            <div class="favorite">
                    <%= render 'vendors/favorite' %>
            </div>
        </td>
        <td><h2><%= image_tag @vendor.image_url %></h2></td>
        <td><%= @vendor.address %></td>
    </tr>
</table>

Here's the partial favorite :

<% if current_user.voted_for?(@vendor) %>
    <%= link_to image_tag("Heart (2).png"), 
        { :controller => :vendors, 
        :action => 'vote_against_vendor', :vendor_id => @vendor.id},
        { :method => 'delete', :remote => true }%>
<% else %>
    <%= link_to image_tag("Heart (1).png"), 
        { :controller => :vendors, 
        :action => 'vote_for_vendor', :vendor_id => @vendor.id},
        { :method => 'post', :remote => true} %>
<% end %>

Here's my relevant controller actions:

respond_to :js

def show

    @vendor = Vendor.find_by_id(params[:id])
end

def vote_for_vendor

    vendor = Vendor.find(params[:vendor_id])
    current_user.vote_for(vendor)
    render :toggle
end

def vote_against_vendor

    vendor = Vendor.find(params[:vendor_id])
    current_user.unvote_for(vendor)
    render :toggle
end

My toggle.js.erb file:

$("#favorite").html("<%= escape_javascript render('favorite') %>");

I'm really new to using js and ajax, please help! Thanks in advance.

ERROR LOG

After committing my remote transaction correctly, I get this error:

Rendered vendors/_favorite.html.erb (1.3ms)
  Rendered vendors/toggle.js.erb (2.6ms)
Completed 500 Internal Server Error in 47ms

ActionView::Template::Error (Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id):
    1: <% if current_user.voted_for?(@vendor) %>
    2:  <%= link_to image_tag("Heart (2).png"), 
    3:      { :controller => :vendors, 
    4:      :action => 'vote_against_vendor', :vendor_id => @vendor.id},
  app/views/vendors/_favorite.html.erb:1:in `_app_views_vendors__favorite_html_erb___385976980778737159_2184308220'
  app/views/vendors/toggle.js.erb:1:in `_app_views_vendors_toggle_js_erb___3800164439665893406_2169792040'
  app/controllers/vendors_controller.rb:39:in `vote_for_vendor'


  Rendered /Users/User/.rvm/gems/ruby-2.0.0-p195/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.7ms)
  Rendered /Users/User/.rvm/gems/ruby-2.0.0-p195/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.3ms)
  Rendered /Users/User/.rvm/gems/ruby-2.0.0-p195/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (11.1ms)

Not sure what this means: ActionView::Template::Error (Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id):

OK, you need to assign the model to an instance not local variable in your controller.

@vendor = Vendor.find(params[:vendor_id])

The rest looks good to me.

Not sure but I guess you may be missing render 'vendors/favorite' in your toggle.js.erb file. Everything else seems to be okay for me.

Ajax is the client side way to send server a request and get a response in several commands. You should do the calling on the client side (so mainly write code on javascript or client side language).

Don't forget that ajax is an asynchronous by default (you can change it - not recommanded at first try. Actually when you send your request to server, you go to next line of your code, and the response is recieved not exactly at the expected time, as usual programs).

Here is a tinny code:

var tout;
....

function checkAjax() {
    'use strict';

    var xmlhttp;

    if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {// code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
            if (tout) {
                clearTimeout(tout);
            }
// do something
        }
    };

    function ajaxTimeout() {
        xmlhttp.abort();
// write error to client
    }

    clearTimeout(tout); // if tout is global.

    tout = setTimeout(function () {
        ajaxTimeout();
    }, 10000); // 10 seconds, or what you persume to be fine.

    xmlhttp.open("POST", "test.php", true); // it can be "GET" or aspx, or whatever.
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    xmlhttp.send("");
}

Good luck!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM