Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Create Method Creating Duplicates

I have a to do list function in my app which appears to be creating duplicate tasks every time I try to enter one. (You can see the error live at https://www.thestaysanemom.com/tasks with the username '[email protected]' and password of 'password'.)

The app uses ajax to function, which I can only imagine is causing the error.

The create method is like this:

  def create
    @task = Task.new(task_params)
    @task.user_id = current_user.id
    if @task.save
      respond_to do |format|
        format.js
        format.html
      end
    else
      render :new
    end
  end

Here's the view where it all takes place:

<% if current_user %>

      <div class="container">
            <div class="row">
                <div class="col-xs-12 col-md-6 col-lg-12">
                <div class="content-box to-do">
                  <h2 class="font-script text-center">One-Time Tasks</h2>
            <p class="text-center">These tasks are here to stay, until you complete them.</p>
                        <div id="onetime-todo"><%= render partial: 'items', locals: { task: @one_time } %></div>
                        <div id="onetime-done"><%= render partial: 'done', locals: { task: @one_time_done } %></div>
                </div> <!-- content box -->
                </div> <!-- col -->

                <div class="col-xs-12 col-md-6 col-lg-4">
                <div class="content-box to-do">
                  <h2 class="font-script text-center">Daily</h2>
                        <p class="text-center">These automatically uncheck at night so you have a fresh list&nbsp;in&nbsp;the&nbsp;morning.</p>
                  <div id="daily-todo"><%= render partial: 'items', locals: { task: @daily } %></div>
                        <div id="daily-done"><%= render partial: 'done', locals: { task: @daily_done } %></div>
                </div> <!-- content box -->
                </div> <!-- col -->

                <div class="col-xs-12 col-md-6 col-lg-4">
                <div class="content-box to-do">
                  <h2 class="font-script text-center">Weekly</h2>
                        <p class="text-center">These automatically uncheck Sunday night so you get a new list&nbsp;each&nbsp;Monday&nbsp;morning.</p>
                  <div id="weekly-todo"><%= render partial: 'items', locals: { task: @weekly } %></div>
                        <div id="weekly-done"><%= render partial: 'done', locals: { task: @weekly_done } %></div>
                </div> <!-- content box -->
                </div> <!-- col -->

                <div class="col-xs-12  col-md-6 col-lg-4">
                <div class="content-box to-do">
                  <h2 class="font-script text-center">Monthly</h2>
                        <p class="text-center">These automatically uncheck on the last day of the month so you start with a clean&nbsp;list&nbsp;each&nbsp;1st.</p>
                  <div id="monthly-todo"><%= render partial: 'items', locals: { task: @monthly } %></div>
                        <div id="monthly-done"><%= render partial: 'done', locals: { task: @monthly_done } %></div>
                </div> <!-- content box -->
                </div> <!-- col -->
            </div> <!-- row -->
      </div> <!-- container -->
<% end %> <!-- current_user -->

<script>
    $(document).ready(function() {
        $('.content-box').matchHeight();

    });
</script>

Here's my create.js.erb:

$("#onetime-todo").html("<%= escape_javascript(render partial: 'items', locals: { task: @one_time }) %>")
$("#onetime-done").html("<%= escape_javascript(render partial: 'done', locals: { task: @one_time_done }) %>")

$("#daily-todo").html("<%= escape_javascript(render partial: 'items', locals: { task: @daily }) %>")
$("#daily-done").html("<%= escape_javascript(render partial: 'done', locals: { task: @daily_done }) %>")

$("#weekly-todo").html("<%= escape_javascript(render partial: 'items', locals: { task: @weekly }) %>")
$("#weekly-done").html("<%= escape_javascript(render partial: 'done', locals: { task: @weekly_done }) %>")

$("#monthly-todo").html("<%= escape_javascript(render partial: 'items', locals: { task: @monthly }) %>")
$("#monthly-done").html("<%= escape_javascript(render partial: 'done', locals: { task: @monthly_done }) %>")

$('#textField').val("");

Which renders _items.html.erb:

<div class="to-do-list taskWrapper" data-url="<%= sort_tasks_path %>">
  <% task.each do |task| %>
  <div id="<%= dom_id(task) %>">
    <%= link_to task do %>
      <p>
        <%= fa_icon "bars", class: "color-neutral-light", style: "margin-right: 5px;" %>
        <%= link_to check_task_path(task), method: :post, remote: true do %>
          <%= fa_icon "square-o", style: "margin-right: 5px;" %>
        <% end %>
        <span id="task-show-hide">
          <span class="font-serif">
            <%= task.name %>
          </span>
          <span>
            <%= link_to task_path(task), method: :delete, remote: true do %>
              <%= fa_icon "remove", id: (task.id.to_s + "task"), style: "margin-left: 5px" %>
            <% end %>
          </span>
        </span>
      </p>
    <% end %> <!-- dom id wrapper -->
  </div>
  <% end %> <!-- task each -->
</div>

<script>
    $(document).on('ready page:load', function() {
        $('.content-box').matchHeight();
    $(".taskWrapper").sortable({

      update: function(e, ui) {
        var $that = $(e.target);

        Rails.ajax({
          url: $(this).data("url"),
          type: "PATCH",
          data: $that.sortable('serialize'),
        });

        console.log(ui.item.index())
      }
    });
    });
</script>

And I don't think it matters, but for completion's sake here's the schema for tasks.

 create_table "tasks", force: :cascade do |t|
    t.string "name"
    t.string "frequency"
    t.boolean "completed", default: false
    t.integer "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "position"
    t.index ["user_id"], name: "index_tasks_on_user_id"
  end

Can anyone see why this is creating duplicates?

Additional Info: ERB Form Creation

        <%= simple_form_for(@create_task, remote: true) do |f| %>
            <div class="row padded">
                <div class="col-xs-12 col-sm-9">
                    <%= f.text_field :name, id: "textField", placeholder: "What needs to get done?", class: "form-control" %>
                </div>
                <div class="col-xs-12 col-sm-3">
                    <%= f.select :frequency, options_for_select([["One-Time", "OneTime"],["Daily", "Daily"],["Weekly", "Weekly"],["Monthly", "Monthly"]]), {}, {class: "form-control"} %>
                </div>
                <div class="container text-center">
                    <div class="half-buffer"></div>
                    <%= f.button :submit, class: "btn btn-outline-secondary" %>
                    <div class="half-buffer"></div>
                </div>
            </div> <!-- row -->
        <% end %>

ADDITIONAL INFORMATION

As requested, here are my required statements inside my application.js.erb:

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require popper
//= require magnific-popup
//= require jquery-ui
//= require froala_editor.min.js
//= require plugins/align.min.js
//= require plugins/char_counter.min.js
//= require plugins/code_beautifier.min.js
//= require plugins/code_view.min.js
//= require plugins/colors.min.js
//= require plugins/font_size.min.js
//= require plugins/fullscreen.min.js
//= require plugins/image.min.js
//= require plugins/image_manager.min.js
//= require plugins/inline_style.min.js
//= require plugins/line_breaker.min.js
//= require plugins/link.min.js
//= require plugins/lists.min.js
//= require plugins/paragraph_format.min.js
//= require plugins/paragraph_style.min.js
//= require plugins/quote.min.js
//= require plugins/special_characters.min.js
//= require plugins/url.min.js

** ADDED GEMFILE **

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.0'

gem 'rails', '~> 5.2.0'
gem 'puma', '~> 3.11'
gem 'puma_worker_killer'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'jbuilder', '~> 2.5'
gem 'mini_magick'
gem 'jquery-rails'
gem 'devise'
gem 'bootsnap'
gem 'bootstrap', '~> 4.1.3'
gem 'jquery-ui-rails'
gem 'sprockets-rails'
gem 'bootstrap-sass'
gem 'bcrypt', '~> 3.1.7'
gem 'friendly_id', '~> 5.2.0'
gem 'stripe'
gem 'figaro'
gem 'magnific-popup-rails', '~> 1.1.0'
gem 'simple_form'
gem 'acts-as-taggable-on', '~> 6.0' #must be this version for Rails5
gem 'aws-sdk' , '~> 3'
gem 'aws-sdk-s3', require: false
gem 'simple_form_extension'
gem 'recaptcha', require: "recaptcha/rails"
gem 'font-awesome-rails'
gem 'trix-rails', require: 'trix'
gem 'rack-tracker'
gem 'high_voltage', '~> 3.1'
gem 'convertkit-ruby', require: 'convertkit'
gem 'dotenv-rails'
gem 'acts_as_list'
gem 'wysiwyg-rails'
gem 'font-awesome-sass'
gem 'will_paginate'

group :production do
  gem 'pg', '~> 0.20.0'
end

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'sqlite3'
end

group :development do
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'binding_of_caller'
  gem 'better_errors'
end

group :test do
  gem 'capybara', '>= 2.15', '< 4.0'
  gem 'selenium-webdriver'
  gem 'chromedriver-helper'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
like image 369
Liz Avatar asked Dec 09 '18 18:12

Liz


1 Answers

Your rails code looks fine, but your form is getting double-submitted when you submit. You should be able to see this in the Chrome dev tools as below.

screenshot

Both of those references point to the application.js file, but different lines. It's hard to tell which libraries are catching the submit because the file is concatenated and doesn't include the debug information. Without seeing which JS files you're using (from application.js), I'd venture a guess that you might have both rails-ujs & jquery_ujs included which is causing the double submit.

Check the related question and answers here: Form submitted twice, due to :remote=>true

Update: You've definitely got both rails-ujs & jquery_ujs present in your compiled JS file. I think that's a good place to look. If you're on Rails 5 and using the jquery-rails gem you might look here: https://github.com/rails/jquery-rails#installation

If you are running Rails 5.1 and up, and if you have 
included //= require rails-ujs, then jquery_ujs is not needed anymore

You just need to remove the //= require jquery_ujs line from your app/assets/javascripts/appplication.js file

like image 111
Jay Dorsey Avatar answered Nov 15 '22 09:11

Jay Dorsey