LoginSignup
10
6

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-04-07

目標

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();
➡︎ 表示を消す

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6