0

I am trying to implement AJAX in my to do type app, but am getting a missing template error (Missing template items/create, application/create with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee]}.) on my create action. There shouldn't be a create.html.erb page because the creation of items happens on a lists#show page:

<div class='new-item'>
  <%= render 'items/form' %>
</div>

<div class="js-items">
  <% @items.each do |item| %>
    <%= div_for(item) do %>
      <p><%= link_to "", list_item_path(@list, item), method: :delete, remote: true, class: 'glyphicon glyphicon-ok', style: "margin-right: 10px" %>
       <%= item.name %>
      <% if item.delegated_to != "" && item.user_id == current_user.id %>
        <small>(Delegated to <%= item.delegated_to %>)</small>
      <% elsif item.delegated_to != "" && item.user_id != current_user.id %>
        <small>(Delegated by <%= item.user_id %>)</small>
      <% end %></p>
    <% end %>
  <% end %>
</div>

And the _form.html.erb partial to which it links:

<div class="row">
  <div class="col-xs-12">
    <%= form_for [@list, @item], remote: true do |f| %>

      <div class="form-group col-sm-6">
        <%= f.label :name %>
        <%= f.text_field :name, class: 'form-control', placeholder: "Enter Item Name" %>
      </div>

      <div class="form-group col-sm-6">
        <%= f.label 'Delegate To (Not Required)' %>
        <%= f.text_field :delegated_to, class: 'form-control', placeholder: "Enter an Email Address" %>
      </div>

      <div class="text-center"><%= f.submit "Add Item to List", class: 'btn btn-primary' %></div>
    <% end %>
  </div>
</div>

Here's the create method in the items_controller:

  def create
    @list = List.friendly.find(params[:list_id])
    @item = @list.items.new(item_params)
    @item.user = current_user
    @new_item = Item.new

    if @item.save
      flash[:notice] = "Item saved successfully."
    else
      flash[:alert] = "Item failed to save."
    end

    respond_to do |format|   <<<<ERROR CALLED ON THIS LINE
      format.html
      format.js
    end
  end

And here's my create.js.erb file:

<% if @item.valid? %>
  $('.js-items').prepend("<%= escape_javascript(render(@item)) %>");
  $('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: @list, item: @new_item }) %>");
<% else %>
  $('.flash').prepend("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert'>&times;</button><%= flash.now[:alert] %></div>");
  $('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: @list, item: @item }) %>");
<% end %>

Anyone have any ideas why I am getting this? I tried removing the format.html line from the items_controller but I got an unrecognizable format error.

Liz
  • 1,369
  • 2
  • 26
  • 61
  • Remove the format.html, you definitely don't need it. However, try to comment out your create.js.erb file but leave a simple console.log to see if the error is coming from what's in the file – Graham Slick Jun 11 '16 at 18:10
  • Without 'format.html` I get `ActionController::UnknownFormat` on the `respond_to do |format|` line. (Even with `console.log` instead of the js file content.) – Liz Jun 11 '16 at 18:18
  • Your form is not successfully requesting with a JS format. That is, the `remote: true` option is not being handled properly. Check this question for a possible solution: http://stackoverflow.com/questions/4227775/rails-form-for-remote-true-is-not-calling-js-method – sealocal Jun 11 '16 at 23:04
  • @sealocal, this post is a great resource, but I have a `javascript_include_tag` and a `csrf_meta_tags` in my application header and I have AJAX deletion working just fine with a JS format. – Liz Jun 12 '16 at 00:22
  • If you remove `remote: true` from your AJAX deletion `link_to` helper, does your AJAX deletion still work? Or are you processing you sending your creation and deletion requests with your own code, such as a click handler on the submit button? – sealocal Jun 12 '16 at 00:33
  • When you inspect the `form` element in the DOM, do you see the `data-remote="true"` attribute? – sealocal Jun 12 '16 at 00:35
  • @sealocal, without `remote: true` the deletion does not work. And it looks like the items are in fact being created before the error appears. – Liz Jun 12 '16 at 00:36
  • And yes, the `data-remote="true"` is in the form. – Liz Jun 12 '16 at 00:37
  • You could try `<%= form_for([@list, @item], format: :js, remote: true) do |f| %>` to ensure that the request specifies a `js` response/format. – sealocal Jun 12 '16 at 00:39
  • No luck. I'm getting this in my server log: ` Rendered items/create.js.erb (8.4ms) Completed 500 Internal Server Error in 26ms (ActiveRecord: 2.0ms) ActionView::MissingTemplate - Missing partial items/_item with {:locale=>[:en], :formats=>[:js, :html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee]}. Searched in: * "/Users/.../bloc/code/blocitoff/app/views" * "/Users/.../.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/devise-4.1.1/app/views"` – Liz Jun 12 '16 at 00:44
  • Also, look at your http request to see the type. Rails determines the desired response format from the HTTP Accept header submitted by the client. Make sure that the request is being generated as a javascript request type. – hightempo Jun 12 '16 at 00:45
  • @hightempo, I have no idea how to do that. – Liz Jun 12 '16 at 00:47
  • Oh, looks like your error has changed. It's now rendering your create.js.erb but is looking for a partial called _item. That is probably because of the line " $('.js-items').prepend("<%= escape_javascript(render(@item)) %>");" – hightempo Jun 12 '16 at 00:50
  • It seems like you have the format issue solved and are now just missing a partial that you really should have, but for future reference you should be able to examine the request through the 'request' object in your controller. If you're using a tool for debugging like pry, put a binding in your controller action and look at request.format. If not, you can inspect it with puts and that will write it to the logs, but it's a huge messy object. – hightempo Jun 12 '16 at 00:57

1 Answers1

0

You can force the form submission to use a JS format, instead of the default HTML format, so that your respond_to block will render the create.js.erb view instead of the create.html.erb view.

<%= form_for([@list, @item], format: :js, remote: true) do |f| %>

Typically, Rails will detect your remote: true option via "unobtrusive JavaScript (ujs)", which will effectively handle the format: :js option for you. There is something unique in your setup that we have not identified, which is requiring you to enforce the format option.

To see that your create.js.erb is working, you can change the line that renders your item partial:

$('.js-items').prepend("<%= escape_javascript(render(@item)) %>");

To render a the item's name, wrapped in a <p> tag:

$('.js-items').prepend("<p>" + <%= @item.name %> + "</p>");

You can customize that line to generate the html that you want to appear for your new list item. Based on your code above, this looks like it will work out for you.

As you finish your to-do app, you can create a partial for your item, and then change that line again so that your partial will be appended to your list of items.

sealocal
  • 10,897
  • 3
  • 37
  • 50
  • All of this worked, except it still requires a manual refresh to get the form to clear and the new item to appear on the list... – Liz Jun 12 '16 at 05:30
  • You should double-check that `$('.js-items)` returns the correct DOM element to which you want to prepend (`
    `). You can run `$('.js-items)` in your browser console. Then you can attempt to prepend arbitrary HTML. It seems there is something in your jQuery code that is not manipulating the DOM the way that you wish.
    – sealocal Jun 12 '16 at 06:12