简体   繁体   中英

How do I specify an AJAX response?

I'm dipping my toe into Rails3 / JQuery / unobtrusive javascript. I've written a toy app that does everything I want with JS disabled, now I want to introduce javascript so the server doesn't have to refresh the entire page on every transaction.

Here's the NON-JS Controller/View environment for creating a new Toy:

controller

class ToysController < ApplicationController
...
def new
  @toys = Toy.all
  @toy = Toy.new
  respond_to do |format|
    format.html               # new.html.erb
  end
end

views

# ========== 
# file: views/toys/index.html.erb
<%= render :partial => 'list', :locals => {:toys => @toys, :target => nil} %>
<%= link_to 'New Toy', new_toy_path, :class => 'new' %>

# ========== 
# file: views/toys/new.html.erb
<%= render :partial => 'list', :locals => {:dj_monitors => @toys, :target => @toy} %>

# ========== 
# file: views/toys/_list.html.erb
<div class='table-div'>
  <div class='body-div'>
    <% toys.each do |t| %>
      <%= render :partial => 'toy', :locals => {:toy => t} %>
    <% end %>
    <% if target && target.new_record? %>
      <%= render :partial => 'form', :locals => {:toy => target} %>
    <% end %>
  </div>
</div>

(Pardon any apparent complexity, but all _list.html.erb does is list all the existing toys, and if :target refers to a new record, renders the _form partial at the end of the list.)

# ========== 
# file: views/toys/_form.html.erb
<%= form_for(toy) do |f| %>
  <div class='column selected'><%= f.number_field :sku %></div>
  <div class='column selected'><%= f.text_field :description %></div>
  <div class='column selected'>
    <%= link_to 'Cancel', toys_path %>
    <%= f.submit %>
  </div>
<% end %>

ajaxification

What I'd like in the javascript enabled version is that clicking on the 'new toy' link (in index.html.erb) submit an XMLHttpRequest that returns only the form partial , which would be rendered in-place. The posting of that form would be a standard remote => true transaction as well.

But I can't figure out how to get the server to return the form only. I modified ToysController's new method to:

def new
  @toys = Toy.all
  @toy = Toy.new
  respond_to do |format|
    format.html               # new.html.erb
    format.js   { render :partial => 'form', :locals => {:toy => @toy} }
  end
end

... and enabled the :remote => true option in the [New Toy] link in the index.html.erb view:

<%= link_to 'New Toy', new_toy_path, :class => 'new', :remote => true %>

Now my proxy web debugger sees GET /toys/new HTTP/1.1 with X-Requested-With: XMLHttpRequest (that looks right), but the response is HTTP/1.1 304 Not Modified

Why isn't it rendering _form.html.erb?

update: avoiding '304 Not Modified' (non-)responses

There were two issues -- @Robin solved the main problem. The other part was that I was getting a "304 Not Modified" response -- it was technically correct, since the server had already sent the form -- but made debugging difficult.

So if you're trying to debug javascript / ajax code, it can help to stick a call to 'expires_now' in your controller to force the server to re-send the page while you're debugging, like this:

def new
  @toy = Toy.new
  expires_now
  respond_to do |format|
    format.html ...
    format.js ....
  end
end
def new
    @toy = Toy.new
    respond_to do |format|
        format.html { @toys = Toy.all } #you only need to get all toys in this case (and you should add pagination)
        format.js
    end
 end

in new.js.erb

$("#some_div").append("<%= escape_javascript(render "toys/form", :toy => @toy) %>")

You would need to render the partial in the format.js if you did the request yourself:

$.ajax({
   success: function(data) {
       $("#some_div").append(data);
   }
})

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