Help us understand the problem. What is going on with this article?

【Rails】Ajaxを用いた非同期投稿・削除の実装

目標

ezgif.com-video-to-gif (3).gif

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

Slim導入
Bootstrap3導入
ログイン機能実装

投稿機能を実装

1.モデル

ターミナル
$ rails g model Book user_id:integer title:string body:text
ターミナル
$ rails db:migrate
schema.rb
ActiveRecord::Schema.define(version: 2020_04_05_115005) do
  create_table "books", force: :cascade do |t|
    t.integer "user_id"
    t.string "title"
    t.text "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end
user.rb
class User < ApplicationRecord
  has_many :books, dependent: :destroy
end
book.rb
class Book < ApplicationRecord
  belongs_to :user
end

2.コントローラー

ターミナル
$ rails g controller books index
books_controll.rb
class BooksController < ApplicationController
  def create
    @book = Book.new(book_params)
    @book.user_id = current_user.id
    if @book.save
      redirect_to book
    else
      @books = Book.all
      render 'index'
    end
  end

  def index
    @book = Book.new
    @books = Book.all
  end

  def destroy
    @books.destroy
    redirect_to books_path
  end

  private

    def book_params
      params.require(:book).permit(:title, :body)
    end
end

3.ルーティング

routes.rb
Rails.application.routes.draw do
  resources :books
end

4.ビュー

books/index.html.slim
.row
  .col-xs-3
    = form_with model: @book, local: true do |f|

      = f.label :title, 'タイトル'
      br
      = f.text_field :title, class:'form-control'
      br

      = f.label :body, '本文'
      br
      = f.text_area :body, class:'form-control'
      br

      = f.submit '投稿', class: 'btn btn-primary btn-block'

  .col-xs-9
    table.table
      thead
        tr
          th
            | 投稿者
          th
            | タイトル
          th
            | 本文
          th

      tbody.new_book
        - @books.each do |book|
          tr
            td
              = link_to book.user  do
                = book.user.name
            td
              = link_to book.title, book_path(book)
            td
              = book.body
            td
              -if book.user == current_user
                = link_to '削除', book, method: :delete, data: { confirm: '本当に削除してもよろしいですか?' }, class: 'btn-sm btn-danger'

非同期機能を実装

1.jQueryを導入

Gemfile
gem 'jquery-rails'
ターミナル
$ bundle
application.js
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery // turbolinksより下に記述
//= require_tree .

2.createアクションを編集

books.controller.rb
class BooksController < ApplicationController
  def create
    @book = Book.new(book_params)
    @book.user_id = current_user.id
    unless @book.save
      @books = Book.all
      render 'index'
    end
  end
end

3.ビューを編集

books/index.html.slim
.row
  .col-xs-3
    / 「local: true」から「remote: true」に変更
    = form_with model: @book, remote: true do |f|

      = f.label :title, 'タイトル'
      br
      / クラスを付与
      = f.text_field :title, class:'form-control book-title'
      br

      = f.label :body, '本文'
      br
      / クラスを付与
      = f.text_area :body, class:'form-control book-body'
      br

      = f.submit '投稿', class: 'btn btn-primary btn-block'

  .col-xs-9
    table.table
      thead
        tr
          th
            | 投稿者
          th
            | タイトル
          th
            | 本文
          th
      / 投稿一覧の親要素にクラスを付与
      tbody.new_book
        - @books.each do |book|
          / 投稿一覧をパーシャル化
          = render 'books', book: book
books/_books.html.slim
/ 各投稿にIDを付与
tr id='book-#{ book.id }'
  td
    = link_to book.user  do
      = book.user.name
  td
    = link_to book.title, book_path(book)
  td
    = book.body
  td
    -if book.user == current_user
      / 「remote: true」を付与
      = link_to '削除', book, method: :delete, data: { confirm: '本当に削除してもよろしいですか?' }, remote: true, class: 'btn-sm btn-danger'

「remote: true」を付与する事で、JavaScriptファイルを呼び出せる様になる。
※ 非同期投稿を行うときは必ず「form_with」を使用する。

5.JavaScriptファイルを作成

books/create.js.erb
$(".book-title").val('');
$(".book-body").val('');
$(".new_book").append("<%= j(render 'books', book: @book) %>");

$(".book-title").val('');
$(".book-body").val('');
➡︎ 入力フォームを空にする

$(".new_book")
➡︎ 「4」で付けたクラスを指定

.append("<%= j(render 'books', book: @book) %>");
➡︎ 既存投稿の後尾に新規投稿を表示
※ 先頭に表示したい場合は「prepend」を使用する。

books/destroy.js.erb
$("#book-<%= @book.id %>").remove();

$("#book-<%= @book.id %>")
➡︎ 「4」で付与したIDを指定

.remove();
➡︎ 表示を消す

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした