ブログアプリ⑨(タグのテーブルを作ろう)

タグのテーブルをつくる

$ rails g model tag tag:string
Running via Spring preloader in process 27600
      invoke  active_record
      create    db/migrate/20181206042331_create_tags.rb
      create    app/models/tag.rb

記事とタグの中間テーブルをつくる

$ rails g model article_tag article:references tag:references
Running via Spring preloader in process 34479
      invoke  active_record
      create    db/migrate/20181206042916_create_article_tags.rb
      create    app/models/article_tag.rb

そうそう。中間テーブルを作るときにreferences型を指定して作ったら、出来上がったモデルファイルに初めからアソシエーションが記述されてた。便利ー

f:id:d_riko:20181206133240p:plain

articleモデルと今作ったtagモデルにもアソシエーションを設定したげる

models/article.rb

class Article < ApplicationRecord
  has_many :article_tags
  has_many :tags, through: :article_tags
end
models/tag.rb

class Tag < ApplicationRecord
  has_many :article_tags
  has_many :articles, through: :article_tags
end

マイグレートする

$ bundle exec rake db:migrate
== 20181206042331 CreateTags: migrating =======================================
-- create_table(:tags)
   -> 0.0384s
== 20181206042331 CreateTags: migrated (0.0386s) ==============================

== 20181206042916 CreateArticleTags: migrating ================================
-- create_table(:article_tags)
   -> 0.0293s
== 20181206042916 CreateArticleTags: migrated (0.0294s) =======================

これで必要なテーブルができた!

f:id:d_riko:20181206134239p:plain

f:id:d_riko:20181206134249p:plain

次はタグを新規につけられるようにするよ

ブログアプリ⑧(タグ機能を考えよう)

タグ機能をつける!

その前に。具体的に何をできるようにするか考える

  • 記事を作成・編集するときにタグをつける
    • 新規のタグを作る
    • 既存のタグを使う
  • 記事からタグを外す
  • タグ一覧
    • リストで出す
    • タグを使ってる記事の数
  • タグを消す
    • 一覧から消す
    • 記事についてるタグも消える

やりたいことはこんなところ

で、だ

タグを何個つけられるようになるかでも難易度が変わることに今更気が付いてしまった……遅いよ

なので、まずは3個固定でつけられるように作る。個数制限をなしにするのはその後で

次は必要なテーブルを作って、新規にタグをつけられるようにするよ

ブログアプリ⑦(記事を編集・削除しよう)

一度投稿した記事を編集or削除できるようにするよ

ところで、記事投稿でつくったコレ使いまわしたいね

f:id:d_riko:20181202155826p:plain

……

部分テンプレ〜!テッテレー

まずはnewのビューファイルに直接書いたフォーム部分を切り出したげる

views/articles/_form.html.haml

= form_for @article do |f|
  = f.text_field :title, placeholder: "タイトルだよ"
  %br
  = f.text_area :text, placeholder: "本文だよ"
  %br
  = f.select :status, Article.article_statuses
  %br
  = f.submit "送信するよ"

空っぽになったnewのビューファイルではテンプレ化したファイルを呼び出すようにする

views/articles/new.html.haml

= render partial: 'form'

さらに編集用のビューファイルを作って、同じテンプレファイルを呼び出す

views/articles/edit.html.haml

= render partial: 'form'

さらにさらに送信ボタンの表示をアクションによって変えるよ

これを

views/articles/_form.html.haml

  = f.submit "送信するよ"

こうして

views/articles/_form.html.haml

  - if action_name == "new"
    = f.submit "送信するよ"
  - else
    = f.submit "更新するよ"

こうじゃ

new f:id:d_riko:20181203092759p:plain

edit f:id:d_riko:20181203092808p:plain

ついでに削除ボタンもつけちゃう

editの時だけ表示させたいので、elseの中に追加

views/articles/_form.html.haml

  - else
    = f.submit "更新するよ"
    = button_to "削除するよ", { action: "destroy", id: @article.id }, method: :delete, data: { confirm: "消す?" }

f:id:d_riko:20181203093132p:plain

できたー

最後にコントローラの中身を少し綺麗にすればOK

controllers/articles_controller.rb

class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :destroy]

  def index
    @articles = Article.where(status: 1).order("created_at DESC")
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)
    @article.save
    redirect_to new_article_path
  end

  def show
  end

  def edit
  end

  def update
  end

  def destroy
    @article.destroy
    redirect_to articles_path
  end

  private
  def article_params
    params.require(:article).permit(:title, :text, :status)
  end

  def set_article
    @article = Article.find(params[:id])
  end
end

これで最低限必要な記事の投稿・表示・編集・削除ができるようになった

次はタグ機能をつくるよ

ブログアプリ⑥(記事を表示しよう)

データを登録できたので、次は表示させる

記事一覧画面で表示するもの

  • タイトル
  • 記事の最初30文字くらい
  • 最終更新日

記事詳細画面で表示するもの

  • タイトル
  • 記事全文
  • 最終更新日

タグ機能やページ送りもつけたいけど、まずは最低限表示できるようにしよう

コントローラでビューに渡すデータを取得して、ビューでデータを表示させるよ

記事一覧

controllerで、Articleのデータの中でstatusが1のデータを登録日降順に表示させる

controllers/articles_controller.rb

  def index
    @articles = Article.where(status: 1).order("created_at DESC")
  end

せっかくなので部分テンプレを使ってみる

views/articles/index.html.haml

= render partial: 'article', collection: @articles
views/articles/_article.html.haml

%ul
  = link_to "/articles/#{article.id}" do
    %li
      = article.title
    %li
      = article.text.truncate(30, omission: "...続きを見る")
    %li
      = article.created_at.to_s(:date)

ひとまずこんな感じにした

f:id:d_riko:20181202211612p:plain

textとcreated_atは少し頑張ったので記録

text

truncateというヘルパーメソッドを使うと、簡単に途中の文字まで表示することができる

デフォルトだと文字数30文字、末尾に「...」が表示される

truncate - リファレンス - - Railsドキュメント

ビューに記述するだけでできるなんて、ヘルパーメソッドってほんと便利

created_at

まず、何も設定しない状態だと、以下のように表示される

f:id:d_riko:20181202212257p:plain

直したい点としては2つ

  • 本の時間を表示したい(デフォルトはUTC
  • 日付だけ表示したい

順に直していこう

日本時間で表示

意外と簡単!以下のように修正すればOK

config/application.rb

    config.time_zone = 'Tokyo'

こちらの記事を参考にしたよ

qiita.com

日付だけ表示

調べたところ2つ方法があった

  1. strftimeメソッドを使う
  2. 日付のフォーマットを変える

strftimeメソッドは簡単に使える

strftime - リファレンス - - Railsドキュメント

ただ、日付を表示したいところに全部書いていくのは面倒なので、フォーマットを変えちゃう

config/initializers/time_formats.rb

Time::DATE_FORMATS[:default] = '%Y年%m月%d日 %H時%M分'
Time::DATE_FORMATS[:datetime] = '%Y年%m月%d日 %H時%M分'
Time::DATE_FORMATS[:date] = '%Y年%m月%d日'
Time::DATE_FORMATS[:time] = '%H時%M分%S秒'
Date::DATE_FORMATS[:default] = '%Y年%m月%d日'

※ファイルがなかったので新規作成

サーバを再起動して設定を適用

あとは表示させたいやつを記述すればOK

= article.created_at
=> 2018年12月02日 16時00分

= article.created_at.to_s(:date)
=> 2018年12月02日

曜日を日本語表記にもできそうだけど、ひとまずこれでOK

こちらの記事を参考にしたよ

qiita.com

記事詳細

記事一覧とほとんど同じかな

controllers/articles_controller.rb

  def show
    @article = Article.find(params[:id])
  end
views/articles/show.html.haml

%ul
  %li
    = @article.title
  %li
    = @article.text
  %li
    = @article.updated_at.to_s(:date)

f:id:d_riko:20181202220332p:plain

次は、投稿した記事の編集と削除をできるようにしよう

ブログアプリ⑤(記事を投稿できるようにしよう)

ビューからデータを送信して、データベースに保存する機能をつくるよ!

View

タイトル、本文、公開or下書きを選ぶ、送信ボタンを置いた

f:id:d_riko:20181202144530p:plain

views/articles/new.html.haml

= form_for @article do |f|
  = f.text_field :title, placeholder: "タイトルだよ"
  %br
  = f.text_area :text, placeholder: "本文だよ"
  %br
  = f.select :status, Article.article_statuses.keys.to_a
  %br
  = f.submit '送信するよ'

なおビューにstatusセレクトボックスの選択項目をベタがきしたくなかったので、modelファイルにenumで項目を書いてビューで呼び出すようにした

models/article.rb

class Article < ApplicationRecord
  enum article_status: {
    "公開する": 1,
    "下書きする": 2
  }
end
Controller

データを新規追加するためにcreateアクションでインスタンスの生成と保存する処理、あとストロングパラメーターを設定する

controllers/article_controller.rb

class ArticlesController < ApplicationController

  def create
    @article = Article.new(article_params)
    @article.save
  end

  private
  def article_params
    params.permit(:title, :text, :status)
  end
end

よーし試しにデータ登録してみるぞ!

f:id:d_riko:20181202145923p:plain

なんでや!

いやいや落ち着いてコンソールを見ようね

f:id:d_riko:20181202145846p:plain

いくつか気になるとこがあるね

  • Unpermitted parameter: ... :article, ...とあるのでarticleモデルが許可されてない?
  • Parametersのstatusで文字が送られてる。本当は番号を飛ばしたい
  • MySQLが動いたあと、createアクションのテンプレート無いよって言われてる。ごめんて

上から順に解決していこう

Unpermitted parameter

ストロングパラメーターを修正。articleモデルを許可してあげるイメージ

controllers/article_controller.rb

  def article_params
    params.require(:article).permit(:title, :text, :status)
  end

詳しくはここを見よう

railsguides.jp

statusで文字が送られてる

ここでやりたいことは下の2つ

  1. DBに番号で登録する
  2. 日本語で表記する

で、1はできたものの2ができなかった

gemのenum_helpを使ってみたもののうまくいかなかったんだよねー。しかもそこまで重要ではないので、妥協して1だけでよいものとして以下のように修正

views/articles/new.html.haml

  = f.select :status, Article.article_statuses
models/article.rb

  enum article_status: {
    active: 1,
    archive: 2
  }
createアクションのテンプレート無いよ

ひとまずnew(記事新規作成)の画面に戻るようにした

記事一覧or記事新規作成を選べるようにしたいなー

controllers/article_controller.rb

  def create
    @article = Article.new(article_params)
    @article.save
    redirect_to new_article_path
  end

よーし、今度こそデータ登録するぞ!

f:id:d_riko:20181202155826p:plain

送信するよ

f:id:d_riko:20181202155838p:plain

できたー!

次は保存したデータをビューで表示するようにするよ

ブログアプリ④(記事投稿機能を作る準備をしよう)

アプリケーションの素はもう作ってあるので、データベースをつくる

$ rake db:create
Created database 'myblog_development'
Created database 'myblog_test'

できたー f:id:d_riko:20181126113316p:plain


続けてArticleモデルを作成

なおrails modelは新しくテーブルを作る時、rails g migrationは作成済みのテーブルを修正・削除したい時に使うものと捉えてる

$ rails g model article title:string, text:text, status:integer
Running via Spring preloader in process 85796
      invoke  active_record
      create    db/migrate/20181126024341_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml

よしよし

できあがったマイグレーションファイルを見てみる f:id:d_riko:20181126114631p:plain

お゛お゛ん゛!?カンマが変なとこについてる!??

落ち着いてrails d modelで一旦削除

で、今度はこれ

$ rails g model article title:string text:text status:integer

できあがったのがこちら

f:id:d_riko:20181126115116p:plain

複数カラムまとめて作るからカンマ入れたけど、いらなかったんだねぇ


このマイグレーションファイルを元にテーブルつくるよ

$ rake db:migrate
== 20181126024931 CreateArticles: migrating =========================
-- create_table(:articles)
   -> 0.0384s
== 20181126024931 CreateArticles: migrated (0.0386s) ================

できたー

f:id:d_riko:20181126115444p:plain


さらにArticleコントローラを作成

何もオプションを設定しないとhelperやcoffeeなどの使わないファイルも作成されるので、それは作らないようにする

ただし書き方がわからず、このコマンドで試しに実行したら作成されちゃった

$ rails g controller article --assets:none --helper:none

この記事で見た通り、config/application.rbに記載してあげるしかないのかなぁ。でもrailsドキュメントにはオプションとして載ってるから書き方の問題な気がする

qiita.com

config/application.rb

module Myblog
  class Application < Rails::Application
    config.generators do |g|
      g.helper false
      g.javascripts false
      g.stylesheets false
      g.test_framework false
    end
  end
end

これでもう一度コントローラ作成

$ rails g controller articles
Running via Spring preloader in process 40742
      create  app/controllers/articles_controller.rb
      invoke  haml
      create    app/views/articles
      invoke  assets
      invoke    coffee
      invoke    scss

必要なファイルだけできたー!

rails g scaffoldすればモデル・コントローラ・ビューを一通り作成できるのだけどね

不要なファイルが多くあるとどれを使えば分からなくなるので、今は必要最低限のものだけ作るようにする


閑話休題

最後にルーティングの設定とビューファイルを作って、画面が表示されることを確認しよう

config/routes.rb

Rails.application.routes.draw do
  root 'articles#index'
end
controllers/articles_controller.rb

class ArticlesController < ApplicationController
  def index
  end
end
views/article/index.html.haml を作成

"Hello world!"

準備完了

rails sでサーバを起動してローカル環境に接続

できたー f:id:d_riko:20181126123254p:plain

これにて準備はOK

次は記事の投稿と表示ができる機能をつくるよ

ブログアプリ③(設計しよう)

少し日を置いたら入れたい機能が増えてしまった

とはいえ心の向くまま手をつけていては終わらないので、最低限実装する機能を決める

まずはそこからだ

前提

  • 記事は誰でも見られる
  • 投稿画面などは自分だけが見られるようにする(URLを秘匿、IDとパスワードでログインしてから操作)

つくる

  • 記事を投稿する
  • 記事を編集・削除する
  • 記事にタグをつける
  • 月別アーカイブ

つくりたい

  • 記事を下書き状態と公開状態にできる
  • 記事にコメントする
  • 記事に絵文字を投げる
  • 記事をマークダウンで書く
  • 画像を投稿する(初めは1枚でいい。できれば複数)
  • アプリ内検索機能

機能を元にデータベースの設計を考える

発生する情報は?

  • 記事タイトル
  • 記事本文
  • 下書きor公開のステータス
  • タグ一覧
  • 記事⇔タグの関連
  • コメント
  • コメントした人の名前
  • 絵文字一覧
  • 記事⇔絵文字の関連
  • 画像一覧
  • 記事⇔画像の関連

テーブルにすると?

  • 記事テーブル
    • タイトル
    • 本文
    • 状態
  • タグ一覧テーブル
  • 記事とタグの中間テーブル
  • コメントテーブル
    • 本文
    • コメントした人
    • コメント先の記事
  • 絵文字テーブル
  • 記事と絵文字の中間テーブル
  • 画像テーブル
    • 画像情報(URL?)
    • 画像を投稿した記事

ER図かいた

f:id:d_riko:20181126112031p:plain


今わからないこと

考え始めたらまた出てくるだろうけど、現時点で実装方法が全然イメージできないのはこの二つ

  • 画像を本文中の好きな場所に挿入する方法
  • 絵文字だけ投げる方法(Slackをイメージ)

それじゃあ最低限のものから作っていこう

初めは記事を投稿して見られるようにするところから

なおデザインはあとから考える

スクールのカリキュラムで某フリマアプリのコピーサイトを作ったときフロントから作り始めたので、今度はバックから作る