Day 2 ~ 8:Scaffold なしでの掲示板作成

 / #cebu #rails

from Qiita:

使用環境

  • 仮想環境 OS: Ubuntu 18.04
  • Ruby:2.51
    • Rails:5.2.2

rails db:migrate

  • Railsドキュメントより
    • rails db:migrate を実行
    • schema_migrations テーブルを調べ、存在しなければ作成
    • db/migrate ディレクトリ内のすべてのマイグレーションファイルを調べる
    • データベースの現在のバージョンと異なるバージョンがあった場合、データベースに適応
    • schema_migrations テーブルの更新

3日目

scaffoldを利用せずに App 作成をし、Scaffold の有難みを知る

前準備

  1. rails s new qiita_routes -d MySQL
  2. Gemfile の miniracer コメントインして、bundle install
  3. Config/database.yml の password 情報編集
  4. rails db:create

前提:知識

ページ作成に必要なもの

  • view
    • 今日はしなかったので、今投稿には未記載
    • view の中身がブラウザに表示される内容
  • controller
    • ページ表示の際、controller を経由して、view をブラウザに返す。
    • controller で設定した action は、controller と同じ名前の view フォルダの中から、action と同じ名前の html ファイルを探してブラウザに返します
  • routing
    • ブラウザと controller を繋ぐ。

ページ表示の流れ

Routing => Controller => Model => View model はデータベース情報が必要なときだけ使用。今回は必要ではないので、とばす。

本段階

controllerを作成

#rails generate controller コントローラ名 (+アクション名)
rails generate controller Users

routingの設定:ブラウザとコントローラをつなぐ

Rails.application.routes.draw do
get 'users', action: :index, controller: 'users'
end
rails routes
# Prefix Verb URI Pattern
# Controller#Action
# users GET /users(.:format)   #追加された行
# users#index          #追加された行

controller:modelとviewをつなぐ

class UsersController < ApplicationController
def index
render plain: 'Hello'
end
end

無事に、ブラウザ上で Hello が表示された。

renderメソッド

上 controller 編集時に用いた、render メソッドは実際に画面に表示される内容を生成する。今回の render の plain オプションを指定すると、文字列を直接表示できる。 Rails の controller で render を省略すると、代わりに app/views/コントローラ名/アクション名.html.erb を用いる。 => ということは controller 作成コマンドは rails g controller コントローラ名 アクション名

参照: Ruby on Rails でページを作成する仕組み by @np_misaki氏

  • Config : アプリケーションの設定情報を格納する
  • /routes.rb : ルーティングを設定する
  • /locales : 辞書ファイル(グローバル対応等)
  • /app : アプリケーション開発中にメインで使用するディレクトリ
  • /controllers..Controller クラスを格納する
  • /models : Model クラスを格納する
  • /views :View クラスを格納する

4日目

モデルを作成

  • model とは
    • データベースを操作する。
    • app/models 下に配置される
    • データベースに含まれるテーブルごとに用意され、データの登録・取得・更新・削除などを行なう

model作成コマンド

# rails generate model モデル名 カラム名:データ型 カラム名:データ型 ...
rails generate model User name:string email:string sex:integer age:integer address:integer attendance:integer opinion:text
# string型は文字型、integer型は整数型

DBの操作

テーブルの作成をする

rails db:migrate

できたテーブルをMySQL側で確認してみる

-- mysql
USE scanashi0307_development;
-- Reading table information for completion of table and column names
-- You can turn off this feature to get a quicker startup with -A
-- Database changed
-- mysql> SHOW TABLES;
-- +------------------------------------+
-- | Tables_in_scanashi0307_development |
-- +------------------------------------+
-- | ar_internal_metadata |
-- | schema_migrations |
-- | users |
-- +------------------------------------+
-- 3 rows in set (0.00 sec)
-- usersテーブルが作成されたことが分かる。
SHOW CREATE TABLE users;
-- | users | CREATE TABLE `users` (
-- `id` bigint(20) NOT NULL AUTO_INCREMENT,
-- `name` varchar(255) DEFAULT NULL,
-- `email` varchar(255) DEFAULT NULL,
-- `sex` int(11) DEFAULT NULL,
-- `age` int(11) DEFAULT NULL,
-- `address` int(11) DEFAULT NULL,
-- `attendance` int(11) DEFAULT NULL,
-- `opinion` text,
-- `created_at` datetime NOT NULL,
-- `updated_at` datetime NOT NULL,
-- PRIMARY KEY (`id`)
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

rails g modelsで設定したカラム名が作成されているのがわかる。

データベースにfooさんのレコードを追加してみる

INSERT INTO `users` (`name`, `email`, `sex`, `age`, `address`, `attendance`, `opinion`, `created_at`, `updated_at`) VALUES ('foo', 'foo@gmail.com', 1, 23, 2, 0, 'foooo', '2017-04-04 04:44:44', '2018-04-04 04:44:44');
-- Query OK, 1 row affected (0.00 sec)

MySQLの中から、追加されているレコードを確認してみる

SELECT * FROM users;
-- +----+------+---------------+------+------+---------+------------+---------+---------------------+---------------------+
-- | id | name | email | sex | age | address | attendance | opinion | created_at | updated_at |
-- +----+------+---------------+------+------+---------+------------+---------+---------------------+---------------------+
-- | 1 | foo | foo@gmail.com | 1 | 23 | 2 | 0 | foooo | 2017-04-04 04:44:44 | 2018-04-04 04:44:44 |
-- +----+------+---------------+------+------+---------+------------+---------+---------------------+---------------------+

rails console から新たにレコードを追加する

user = User.create(name: "taro", email: "val@gmail.com", sex: 0, address: 1, attendance: 1, opinion: 'nothing special')
#user.saveでDBに保存する
user.save
# => true

Rails Console上でレコード取得

User.all # get all users from record
User.all.last # get last added user from record
first_user = User.all.first # get all users and then get the first user
first_user.destroy # delete the first user
user = User.all.first
user.name = "ichitaro" # overwrite the name with 'ichitaro
user.save # save the data
User.all.count # count the number of all users
User.find_by(id:2) # get a user with id:2

controller

class UsersController < ApplicationController
def index
@users = User.all
end
end

view

<body>
<h1>Users</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Sex</th>
<th>Age</th>
<th>Address</th>
<th>Attendance</th>
<th>Opinion</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= user.sex %></td>
<td><%= user.age %></td>
<td><%= user.address %></td>
<td><%= user.attendance %></td>
<td><%= user.opinion %></td>
</tr>
<% end %>
</tbody>
</table>
</body>
<!DOCTYPE html>
<html>
<head>
# 割愛
</head>
<body>
<%= yield %>
</body>
</html>

ルーティングを変更

resources :users

rails routes実行

# =>
# Prefix Verb URI Pattern Controller#Action
# users GET /users(.:format) users#index
# POST /users(.:format) users#create
# new_user GET /users/new(.:format) users#new
# edit_user GET /users/:id/edit(.:format) users#edit
# user GET /users/:id(.:format) users#show
# PATCH /users/:id(.:format) users#update
# PUT /users/:id(.:format) users#update
# DELETE /users/:id(.:format) users#destroy
# ...

次に上にある、「users GET /users(.:format) users#index」を実装 UserController の中に show アクションを作成

class UsersController < ApplicationController
def index
@users = User.all
end
# 下が追加したshowアクション
def show
end
end
# user.nameのラインを下の様に変更
<td><%= link_to user.name, user_path(user.id) %></td>
# <% link_to ("A"."/B") %>
# 上はhtml上で <a href="/B">A</a>に変化する。

この時点でrails sで立ち上げると

showアクション

  • users_path は users#index へのリンク
  • new_user_path は users#new へのリンク
  • edit_user_path は users#edit へのリンク
  • user_path は users#show へのリンク
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= @user.name %>
</p>
<p>
<strong>Email:</strong>
<%= @user.email %>
</p>
# 割愛
<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>

show, edit アクションの定義

def show
@user = User.find params[:id]
end
def edit
@user = User.find(params[:id])
end
<%= form_with(model: @user, local: true) do |form| %>
<% if @user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this @user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.text_field :email %>
</div>
<div class="field">
<%= form.label :sex %>
<%= form.number_field :sex %>
</div>
# 割愛
<% end %>

追加:2日目を参考にし、表示を触ってみる

性別の値 0 or 1 を男性 or 女性で表示させる。

class User < ApplicationRecord
enum sex: { male: 0 ,female: 1}
end

男性、女性で表示されるようになった。だが、edit ページは、テキスト入力のままだ。

ラジオボタンに変更

<div class"field">
<%= form.label :sex %>
<%= form.radio_button :sex, 'male' %>男性
<%= form.radio_button :sex, 'female' %>女性
</div>

同様に、年齢、住所、参加不参加もラジオボタンにしておく。

user = User.find_by(name:"foo") # get a user named 'foo'
user.age = 0 # rewrite the user's data about age with 0
user.save
User.find_by(name: "foo") # confirm
# =>
# <User id: 1, name: "foo", email: "foo@gmail.com", sex: "女性", age: 0, address: "日本以外", attendance: "参加", opinion: "foooo", created_at: "2017-04-04 04:44:44", updated_at: "2019-03-08 00:07:47"

年齢のラジオボタンを追加


8日目

users_controller

def update
@user = User.find params[:id]
if @user.update(params.require(:user).permit(:name, :email, :sex, :age, :address, :attendance, :opinion))
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end
def destroy
@user = User.find params[:id]
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
end
end
def new
@user = User.new
end

indexページからのdestroyへのリンク作成

<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>

newページ編集

<h1>New User</h1>
<%= form_with(model: @user, local: true) do |form| %>
<% if @user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.text_field :email %>
</div>
# 割愛
<% end %>
<%= link_to 'Back', users_path %>

indexからnewへのリンク作成

<%= link_to 'New User', new_user_path %>

createアクション定義

def create
@user = User.new(params.require(:user).permit(:name, :email, :sex, :age, :address, :attendance, :opinion))
if @user.save
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end

リファクタリング

wikipedia

リファクタリング (refactoring) とは、コンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理することである。

createアクションとupdateアクションの共通化

2 アクションに下の共通箇所がある

@user = User.new(params.require(:user).permit(:name, :email, :sex, :age, :address, :attendance, :opinion))

リファクタリング後

def create
@user = User.new(user_params)
if @user.save
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end
def update
@user = User.find params[:id]
if @user.update(user_params)
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end
private
def user_params
params.require(:user).permit(:name, :email, :sex, :age, :address, :attendance, :opinion)
end
end

show. edit. updata, destroyの共通化

# 共通している部分
@user = User.find params[:id]
# 共通化した結果
# set_user追加
def set_user
@user = User.find params[:id]
end
# before_action追加
# show, edit, update, destroyアクションの前に、必ず実行の意
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]

アクションのリファクタリング後(全体)

class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
@users = User.all
end
def show; end
def edit; end
def update
if @user.update(user_params)
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
end
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
respond_to do |format|
format.html { redirect_to @user, notice: 'User was successfully updated.' }
end
else
respond_to do |format|
format.html { render :edit }
end
end
end
private
def set_user
@user = User.find params[:id]
end
def user_params
params.require(:user).permit(:name, :email, :sex, :age, :address, :attendance, :opinion)
end
end