LoginSignup
46
47

More than 3 years have passed since last update.

Rails 爆速でtag機能を搭載したtodoアプリを作ってみよう(docker構築有)

Posted at

今日の目標

爆速でtag機能を搭載したミニアプリを制作してみる

まずは基本機能のみのアプリを作り 追加実装を意識した作りをする

環境

Ruby 2.5.1
Rails 5.2.4
docker 19.03.8

今回はdockerで環境構築します。

dockerなんて 訳わからんと言う人はdockerの構築部分は読み飛ばしてください

githubでリポジトリも作成します

githubなんて知らんわ って人も読み飛ばしてください

実装内容

タスク作成時・更新時に、事前に作成したラベルを複数付けられるようにする。
タスクに関連付けられているラベルを表示できるようにする。
タスクをラベルで絞り込みできるようにする。

dcocker構築

docker公式

まずディレクトリを作成

$ mkdir todo-tag-app
$ cd todo-tag-app

githubで新しいレポジトリを作成

Image from Gyazo

名前は適当で良いが今回はtodo-tag-appとする

Image from Gyazo

Create repositoryすると

Image from Gyazo

ガイダンスが出てくるので この通りにコマンド打てばgit連携できます

$ git init

今回は機能拡張するかもしれないので ReadMeも作っておきましょう

$ echo "# todo-tag-app" >> README.md

$ git add README.md

結果にcommit

$ git commit -m "first commit"

ファイルをリポジトリに

$ git remote add origin git@github.com:higakikeita/todo-tag-app.git
$ git push -u origin master

無事 Githubと連携できました
Image from Gyazo

dockerの構築

docker-file作成

$ touch Dockerfile

VscodeでDockerfileが作られていることを確認

Image from Gyazo

dockerfileを以下のように編集

Dockerfile
FROM ruby:2.5.1

# 必要なパッケージのインストール(基本的に必要になってくるものだと思うので削らないこと)
RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs           

# 作業ディレクトリの作成、設定
RUN mkdir /app_name 

# 作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照

ENV APP_ROOT /app_name 
WORKDIR $APP_ROOT

# ホスト側(ローカル)のGemfileを追加する(ローカルのGemfileは【3】で作成)
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

# Gemfileのbundle install
RUN bundle install
ADD . $APP_ROOT

結果にcommit

$ git add .
$ git commit -m "Dockerfileの作成"

Gemfileの作成

$ touch Gemfile
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.4'

Gemfile.lockの作成

$ touch Gemfile.lock

結果にcommit

$ git add .
$ git commit -m "Gemfileの作成"

docker-compose.ymlの作成

$ touch docker-compose.yml
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"

  web:
    build: .
    command: rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "3000:3000"
    links:
      - db

結果にcommit

$ git add .
$ git commit -m "docker-compose.yml"

ここまでで アプリケーション作成のためのgithubとdockerの構築はひとまず完了

$ git push

Rails new

$ docker-compose run web rails new . --force --database=mysql --skip-bundle

結果にcommit

$ git add .
$ git commit -m "Rails作成"

database.ymlの編集

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # docker-compose.ymlのMYSQL_ROOT_PASSWORD
  host: db # docker-compose.ymlのservice名

ここまでで一旦 結果にcommit & pushする

$ git add .
$ git commit -m "database.ymlの編集”
$ git push

dockerを起動する

$ docker-compose build # コンテナをビルド

# -dオプションをつけてバックグラウンド実行するとこの後新しいシェルを立ち上げる必要がなくなる
$ docker-compose up # コンテナの一斉起動

dockerのコマンドの基本はこちらでどうぞ
docker-composeコマンドの備忘録
https://qiita.com/tegnike/items/bcdcee0320e11a928d46

DB作成

新しいターミナルを開いて /todo-tag-app で実行

$ docker-compose run web rails db:create

localhost:3000でサーバの起動を確認する

Image from Gyazo

Railsが皆さんを歓迎してくれていますね。

ここまでで環境構築は完了です。いよいよアプリケーションを作っていきます。

爆速でtodoアプリを作成する

それでは 爆速でtodoアプリを作成していきます

まずTaskモデル・コントローラー・ビューをscaffoldで一括生成します。

$ rails generate scaffold task title:string

次にLabelもscaffoldで一括生成してしまいましょう。

$ rails generate scaffold label name:string

結果にcommit

$ git add .
$ git commit -m "タスク、ラベルモデルの作成"

今回は多対多の関連付けを行うので、結合モデル・中間テーブル(交差テーブル)を作りましょう。

$ rails generate model labelling task:references label:references 

ここで 一旦 マイグレーションを実行します

$ docker-compose run web rails db:migrate

Image from Gyazo

Image from Gyazo

Image from Gyazo

schema.rbが以下のようになっているか確認してください
Image from Gyazo

ここまで確認したら 結果にcommit

$ git add .
$ git commit -m "テーブルの作成"

アソシエーション

中間テーブルの作り方はこちらのドキュメント
Active Recordの関連付

TaskモデルとLabelモデルにhas_many :throughを使って、多対多の関連付けを指定します。

app/models/task.rb
class Task < ApplicationRecord
  has_many :labellings, dependent: :destroy
  has_many :labels, through: :labellings
end
app/models/label.rb
class Label < ApplicationRecord
  has_many :labellings, dependent: :destroy
  has_many :tasks, through: :labellings
end

中間テーブルのlabellingモデル

app/models/labelling.rb
class Labelling < ApplicationRecord
  belongs_to :task
  belongs_to :label
end

ここでまた 結果にcommit

$ git add .
$ git commit -m "アソシエーションの設定"
$ git push

ルーティングの設定

config/route.rb
Rails.application.routes.draw do
  root 'tasks#index'
  resources :labels
  resources :tasks

end

ここで一度サーバを再起動し、ビューを確認します。

$ docker-compose up --build

Image from Gyazo

タスク作成・更新時にラベルを関連付けられるようにする

app/views/tasks/_form.html.erbのform_withヘルパーの中に、ラベルを選択できるチェックボックスを作ります。

app/views/tasks/_form.html.erb
<%= form.collection_check_boxes(:label_ids, Label.all, :id, :name) %>
app/views/tasks/index.html.erb
<%= form_with(model: task, local: true) do |form| %>
  <% if task.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(task.errors.count, "error") %> prohibited this task from being saved:</h2>

      <ul>
      <% task.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>
 ここに追加
  <div class="field">
      <%= form.collection_check_boxes(:label_ids, Label.all, :id, :name) %>
    </div>
  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>


次にチェックボックスで選択したラベルをtasks_controller.rbのStrong Parametersで受け取れるようにしましょう。
ラベルを配列で送っているので、書き方が少し複雑になります。

app/controllers/tasks_controller.rb
private

def task_params
  params.require(:task).permit(:title, { label_ids: [] })
end

タスクに関連づけられているラベルを表示できるようにする

app/views/tasks/index.html.erb
<% @tasks.each do |task| %>
      <tr>
        <td><%= task.title %></td>
        <td><%= link_to 'Show', task %></td>
        <td><%= link_to 'Edit', edit_task_path(task) %></td>
        <td><%= link_to 'Destroy', task, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        <%# ここから追加 %>
         <td>
            <% task.labels.each do |label| %>
              <%= label.name %>
            <% end %>
          </td>
        <%# ここまで編集 %>
      </tr>
    <% end %>

まめに結果にcommitしておきましょう

$ git add .
$ git commit -m "ラベル表示の実装"

ラベルでタスクを絞り込めるようにする

まずはタスク一覧画面にセレクトボックスを作成して、絞り込みたいラベルのidをtasks_controllerのindexアクションに渡せるようにしましょう。

app/views/tasks/index.html.erb
<%= form_with url: tasks_path, method: :get, local: true do |form| %>
  <%= form.select("label_id", Label.pluck(:name, :id), { include_blank: true }) %>
  <%= form.submit 'Search', name: nil %>
<% end %>

controller側

app/controllers/tasks_controller.rb
def index
 @tasks =Task.all
 @tasks =@tasks.joins(:labels).where(labels:{id:params[:label_id]})if params[:label_id].present?
end

@tasks.joins(:labels)でlabelsテーブルを結合します。
そして、where(labels: { id: params[:label_id] })で、先ほど設定したセレクトボックスから送られてきたparams[:label_id]と、idが一致するラベルを持つタスクを取得できます。

結果にcommit

$ git add .
$ git commit -m "ラベル絞り込みの実装"
$ git push

ページ遷移の確認

ラベル登録ページとタスク登録ページが今のままだと遷移できないので link_to で遷移できるようにします。

pathを確認

$ rails routes

Image from Gyazo

タスク一覧ページは tasks_path ラベル一覧ページは labels_path

app/view/tasks/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Tasks</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th colspan="3"></th>
    </tr>
  </thead>
      <%= form_with url: tasks_path, method: :get, local: true do |form| %>
      <%= form.select("label_id", Label.pluck(:name, :id), { include_blank: true }) %>
      <%= form.submit 'Search', name: nil %>
    <% end %>

  <tbody>
    <% @tasks.each do |task| %>
      <tr>
        <td><%= task.title %></td>
        <td><%= link_to 'Show', task %></td>
        <td><%= link_to 'Edit', edit_task_path(task) %></td>
        <td><%= link_to 'Destroy', task, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        <%# ここから追加 %>
         <td>
            <% task.labels.each do |label| %>
              <%= label.name %>
            <% end %>
          </td>
        <%# ここまで編集 %>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Task', new_task_path %>
<%# この行を追記 %>
<%= link_to "ラベルを登録する",labels_path%>

<%= link_to "ラベルを登録する",labels_path%>を追記します

app/views/labels/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Labels</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @labels.each do |label| %>
      <tr>
        <td><%= label.name %></td>
        <td><%= link_to 'Show', label %></td>
        <td><%= link_to 'Edit', edit_label_path(label) %></td>
        <td><%= link_to 'Destroy', label, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Label', new_label_path %>
<%# ここから追記 %>
<%= link_to "タスクを登録する",tasks_path%>

最後に結果にcommit しておきましょう

$ git add .
$ git commit -m "画面遷移の調整"
$ git push

完成品

Image from Gyazo

基本機能は以下です
タスク作成時・更新時に、事前に作成したラベルを複数付けられる
タスクに関連付けられているラベルを表示できる
タスクをラベルで絞り込みできる

ここからログイン機能を付けたり、カレンダー機能と連携させたり、マークダウン を導入したり いろいろ出来るかと思います。
ビューもいじると結構見栄えのするアプリになるんじゃないかと思います。

檜垣慶太
https://twitter.com/keitah0322

46
47
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
46
47