LoginSignup
2
1

More than 3 years have passed since last update.

Rails6.1ハンズオン(1)~掲示板基本機能実装

Last updated at Posted at 2021-02-18

ターゲット

  • Rails、Rubyを全く知らない人
  • 何らかのプログラミング言語でコードを書いたことがある人
  • ある程度shellの操作に慣れている人
  • macがなくてwindowsしかない人

目的

Rails6.1で基本的な機能を雑に触れながらそれっぽいアプリを作る

やること

  • Gitの設定
  • ログインなしで書き込めるネット掲示板を作る
  • ベースはこれを使う + vscodeに拡張機能を入れて開発

1. 開発環境を整える

1-1. vscodeを整える

vscodeをインストールする。

Visual Studio Code - コード エディター | Microsoft Azure

これでWSLに接続して開発できる(これ以降の拡張機能は必要に応じてWSL上にインストールされる。)

Remote - WSL - Visual Studio Marketplace

日本語化

Japanese Language Pack for Visual Studio Code - Visual Studio Marketplace

アイコンをわかりやすく表示

Material Icon Theme - Visual Studio Marketplace

Ruby関連

Ruby - Visual Studio Marketplace

補完とかしてくれる言語サーバ solargraphさん

# solargraphをインストール
gem install solargraph

Ruby Solargraph - Visual Studio Marketplace

endを自動で入れてくれる

endwise - Visual Studio Marketplace

draw.ioを使いたい

Draw.io Integration - Visual Studio Marketplace

1-2. Gitを整える

first commit

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

github SSH認証の準備

参考にさせていただくもの:
WSL2 から起動した VSCode DevContainer に SSH agent で Git の鍵を渡す - Qiita

cd ~
ssh-keygen -t ed25519 -P ""
# 何も入れずにEnter
cd .ssh
more id_ed25519.pub
# 内容をコピー

Build software better, together

SSH and GPG keysで「New SSH Key」ボタンを押す。
わかりやすいTitle(WSL2とか)を入力、Keyにコピーした公開鍵を貼り付け、Add

~/.bashrcを開いて以下のコードを追加

if [ -z "$SSH_AUTH_SOCK" ]; then
   # Check for a currently running instance of the agent
   RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
   if [ "$RUNNING_AGENT" = "0" ]; then
        # Launch a new instance of the agent
        ssh-agent -s &> $HOME/.ssh/ssh-agent
   fi
   eval `cat $HOME/.ssh/ssh-agent`
fi

ssh-add $HOME/.ssh/id_ed25519

github上にリポジトリを新規作成、(ここでは「Rails6.1_hands_on」という名前)

git remote add origin git@github.com:hirorocky/Rails6.1_hands_on.git
git push -u origin master
# Rails6.1だとまだ”master”

2. 掲示板を作る

2-0. Railsの基礎知識:MVCモデル

詳しくは「Rails MVC」で検索!
私は正しく理解している自信はないですが、こんな図を描いてみました↓

Untitled.png
リクエストが来たら、Rails上のroutes.rbがコントローラーとアクション(=メソッド)を決めて、コントローラー上のアクションでモデルからデータを取りながら、ビューを作って、その結果をブラウザに返すイメージです。

2-1. 設計

◆モデル図

(拡張機能により、〇〇.drawioというファイルを作ればvscode上でdraw.ioが使える!)
Untitled 1.png

◆ワイヤーフレーム(?詳しくない)

Untitled 2.png

4枚のページが必要そう。

  • communities_controller#index:トップページ
  • communities_controller#new→#create:コミュニティ作成ページ
  • communities_controller#show:1つのコミュニティ&コメント一覧
  • comments_controller#new→#create:コメント投稿ページ

なぜこのコントローラー×アクションの組み合わせなのかは聞かないでください。

2-2. 実装

2-2-1. モデル

DB上に各テーブルを作る。

' rails generate model <モデル名> <カラム名>:<型>...'

でモデルに関するファイルを自動で作ってくれる。

rails generateはrails gと省略できる。※以降gで書きます。

rails g model Community title:string owner_name:string
rails g model Comment author_name:string content:text community:references

db/migrateフォルダ内に、2つのファイル(マイグレーションファイル)ができる。

以下のコマンドでDBにテーブルを作成する。

# sqlite上にRails用DBを作成
rails db:setup
# DB上にマイグレーションファイルをもとにテーブルを作成
rails db:migrate

app/models/community.rbにて

class Community < ApplicationRecord
  has_many :comments
end

app/models/comment.rbにて

class Comment < ApplicationRecord
  belongs_to :community
end

こうするだけで、RailsのORMがいい感じにしてくれる。

※ちょっと試すにはターミナルでrails console(rails cでも可)コマンド。

irb(main):001:0> commu = Community.create(title: 'コミュニティタイトルです', owner_name: 'たろう')
   (0.4ms)  SELECT sqlite_version(*)
  TRANSACTION (0.1ms)  begin transaction
  Community Create (0.5ms)  INSERT INTO "communities" ("title", "owner_name", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "コミュニティタイトルです"], ["owner_name", "たろう"], ["created_at", "2021-02-13 02:21:28.386695"], ["updated_at", "2021-02-13 02:21:28.386695"]]
  TRANSACTION (5.0ms)  commit transaction
=> #<Community id: 1, title: "コミュニティタイトルです", owner_name: "たろう", created_at: "2021-02-13 02:21:28.386695000 +0000", updated_at: "2021-02-13 02:21:28.386695000 +0000">

irb(main):002:0> commu.title
=> "コミュニティタイトルです"

irb(main):003:0> commu.comments.create(author_name: 'じろう', content: "コメント\nああああ")
  TRANSACTION (0.1ms)  begin transaction
  Comment Create (0.5ms)  INSERT INTO "comments" ("author_name", "content", "community_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["author_name", "じろう"], ["content", "コメント\nああああ"], ["community_id", 1], ["created_at", "2021-02-13 02:26:21.103087"], ["updated_at", "2021-02-13 02:26:21.103087"]]
  TRANSACTION (5.1ms)  commit transaction
=> #<Comment id: 1, author_name: "じろう", content: "コメント\nああああ", community_id: 1, created_at: "2021-02-13 02:26:21.103087000 +0000", updated_at: "2021-02-13 02:26:21.103087000 +0000">

irb(main):004:0> commu.comments.create(author_name: 'じろう', content: "コメント2\nああああ")
  TRANSACTION (0.1ms)  begin transaction
  Comment Create (0.5ms)  INSERT INTO "comments" ("author_name", "content", "community_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["author_name", "じろう"], ["content", "コメント2\nああああ"], ["community_id", 1], ["created_at", "2021-02-13 02:26:35.918169"], ["updated_at", "2021-02-13 02:26:35.918169"]]
  TRANSACTION (7.1ms)  commit transaction
=> #<Comment id: 2, author_name: "じろう", content: "コメント2\nああああ", community_id: 1, created_at: "2021-02-13 02:26:35.918169000 +0000", updated_at: "2021-02-13 02:26:35.918169000 +0000">

irb(main):005:0> commu.comments
  Comment Load (0.2ms)  SELECT "comments".* FROM "comments" WHERE "comments"."community_id" = ? /* loading for inspect */ LIMIT ?  [["community_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Comment id: 1, author_name: "じろう", content: "コメント\nああああ", community_id: 1, created_at: "2021-02-13 02:26:21.103087000 +0000", updated_at: "2021-02-13 02:26:21.103087000 +0000">, #<Comment id: 2, author_name: "じろう", content: "コメント2\nああああ", community_id: 1, created_at: "2021-02-13 02:26:35.918169000 +0000", updated_at: "2021-02-13 02:26:35.918169000 +0000">]>

ログを見ると、rubyのコードをSQLに変換して、DBを操作しているのがなんとなくわかると思います。

ここでは見ませんが、上記コードだけで、DBに1つのcommunityレコードと2つのcommentレコードができています。

2-2-2. Communityのコントローラー・ビュー

◆コントローラー

rails g controller communities index new create show

設計段階で必要なコントローラーとビューがわかったので、

上記コマンドを入力。すると色々作成される(いらないものもできてしまう...※この辺は設定でいい感じにできますがここでは触れません)

app/controllers/communities_controller.rbのアクションの中にコードを入れる

class CommunitiesController < ApplicationController
  def index
    @communities = Community.all
  end

  def new
    @community = Community.new
  end

  def create
    @community = Community.new(community_params)
    if @community.save
      redirect_to communities_path
    else
      render :new
    end
  end

  def show
    @community = Community.find(params[:id])
    @comments = @community.comments
  end

  private

  def community_params
    params.require(:community).permit(:title, :owner_name)
  end
end

@hogeはインスタンス変数で、この文脈で必要な知識としては、

「インスタンス変数はビューに渡せる」ということです。

community_paramsメソッドはStrong Parameterというやつです。セキュリティ的に必要なもので、詳しくはググってください。

◆ルーティング

Rails.application.routes.draw do
  root to: 'communities#index'
  resources :communities, only: %i[index new create show]
end

自動生成されたものは全部削除、ルートをcommunities_controllerのindexアクションに割りあて、resourcesメソッドでcommunities_controller関連のルーティングを一気に作成。

rails routes

で設定されているルーティングを見ることができ、またもっと見やすくしたいときは、

ブラウザ上で「http://[::1]:3000/rails/info/routes」で見れる。

◆ビュー

ビュー関連はapp/viewsの中に入っている。

自動で作成されたcreate.html.erbはいらないので削除。

早くhamlを使いたい。

一旦、見た目ガン無視の最低限の機能を実装する。

app/views/communities/index.html.erb

<h1>掲示板</h1>

<%= link_to 'コミュニティ作成', new_community_path %>

<% @communities.each do |community| %>
  <div>
    <p><%= link_to community.title, community_path(community) %></p>
    <p><%= community.created_at %></p>
    <p><%= community.owner_name %></p>
  </div>
<% end %>

<% %>の中にrubyのコードを入れることができる。

<%= %>はrubyの評価結果をそのままhtmlに書き出す。

=かそうじゃないかは慣れだと思う。

app/views/communities/new.html.erb

<h1>コミュニティ作成</h1>

<%= form_with model: @community do |form| %>
  <%= form.label :title %>
  <%= form.text_field :title %>
  <%= form.label :owner_name %>
  <%= form.text_field :owner_name %>

  <%= form.submit '作成' %>
<% end %>

※form_withは一時期デフォルトがremote: trueだったが、local: trueになった。

app/views/communities/show.html.erb

<h1><%= @community.title %></h1>

<% @comments.each do |comment| %>
  <div>
    <p><%= comment.author_name %></p>
    <p><%= simple_format(comment.content) %></p>
    <p><%= comment.created_at %></p>
  </div>
<% end %>

2-2-3. Commentのコントローラー・ビュー

◆コントローラー

rails g controller comments new create

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
  before_action :set_community

  def new
    @comment = @community.comments.new
  end

  def create
    @comment = @community.comments.new(comment_params)
    if @comment.save
      redirect_to community_path(@community)
    else
      render :new
    end
  end

  private

  def set_community
    @community = Community.find(params[:community_id])
  end

  def comment_params
    params.require(:comment).permit(:author_name, :content)
  end
end

◆ルーティング

Rails.application.routes.draw do
  root to: 'communities#index'
  resources :communities, only: %i[index new create show] do
    resources :comments, only: %i[new create]
  end
end

rails routesコマンドでこうなる。

Prefix                Verb URI Pattern                                       Controller#Action
                 root GET  /                                                 communities#index
   community_comments POST /communities/:community_id/comments(.:format)     comments#create
new_community_comment GET  /communities/:community_id/comments/new(.:format) comments#new
          communities GET  /communities(.:format)                            communities#index
                      POST /communities(.:format)                            communities#create
        new_community GET  /communities/new(.:format)                        communities#new
            community GET  /communities/:id(.:format)                        communities#show

◆ビュー

app/views/communities/show.html.erb

<%= link_to '←戻る', communities_path %>
<h1><%= @community.title %></h1>

<%= link_to 'コメントする', new_community_comment_path(@community) %>

<% @comments.each do |comment| %>
  <div>
    <p><%= comment.author_name %></p>
    <p><%= simple_format(comment.content) %></p>
    <p><%= comment.created_at %></p>
  </div>
<% end %>

app/views/comments/new.html.erb

<%= link_to '←戻る', community_path(@community) %>
<h1>コメントする</h1>

<%= form_with model: [@community, @comment] do |form| %>
  <%= form.label :author_name %>
  <%= form.text_field :author_name %>

  <%= form.label :content %>
  <%= form.text_area :content %>

  <%= form.submit '投稿' %>
<% end %>

app/views/comments/create.html.erbは削除。

2-2-4. Gemfileの変更

左上に出ている表示が邪魔なので、rack-mini-profilerを削除。

デバッグ用にpry-railsを入れる。

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

ruby '3.0.0'

gem 'rails', '~> 6.1.2', '>= 6.1.2.1'
gem 'sqlite3', '~> 1.4'
gem 'puma', '~> 5.0'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
# gem 'redis', '~> 4.0'
# gem 'bcrypt', '~> 3.1.7'
gem 'bootsnap', '>= 1.4.4', require: false

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

group :development do
  gem 'web-console', '>= 4.1.0'
  # gem 'rack-mini-profiler', '~> 2.0'
  gem 'listen', '~> 3.3'
  gem 'spring'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

ひとまず完成。

次回:Rails6.1ハンズオン(2)~見た目をそれっぽくする

2
1
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
2
1