LoginSignup
1
2

More than 3 years have passed since last update.

Rails1 MVCとは(勉強メモ)

Posted at

※勉強メモです。

Rails(Webアプリケーションフレームワーク )

ユーザがHTTPリクエストの4つのCRUD(POST、GET、PUT、DELETE)を使って、Web上のリソースを操作するアプリケーション
Web上のリソースとは、Webページに表示されるすべて
ただし、ユーザに変更権限があるものとないものがある

・MVC役割構造

URLとHTTPメソッドを受取り、Controllerに渡すのが、Router
リソース(データ)として振舞うのが、Model
Modelを表示・整形するひな形が、View
ModelやViewを制御するのが、Controller

・Rails開発の流れ

1.Model:リソースであり操作対象であり扱うデータを決める
2.Router:Modelを置くURLを決定
3.ルーティングごとに
(1)Controller
(2)View

・Railsプロジェクト作成コマンド

rails new プロジェクト名

・Bundler

RubyやRailsのプロジェクトで使用するライブラリの管理ツール
Gemfileというファイルにインストールしたいライブラリ名と必要なバージョンの一覧を全て書き出し、bundle installで一気にそれらのライブラリをインストールできる
『gem 'ライブラリ名', 'バージョン指定'』

# バージョン 5.2.x の内、最新をインストールする
gem 'rails', '~> 5.2.2'

# バージョン 0.4.4 以上で 0.6.0 未満の中で、最新のライブラリをインストールする
gem 'mysql2', '>= 0.4.4', '< 0.6.0'

# 最新のライブラリをインストールする(バージョン指定無し)
gem 'spring'
・Gitでバージョン管理

プロジェクト作成後はまずコミットしておく

(リポジトリの初期化)
ターミナル、cdで作成フォルダに移動した時(master)と書かれていれば初期化不要。入っていない場合はgit intでバージョン管理を開始

$ git add . #フォルダ内全て選択
$ git commit -m "init Rails Project" #-mを付けてcommit
$ git branch -M main #ブランチ名をmainに変更  

(REPLとは)
Read-eval-printloopの略で「読込み-処理-表示」の繰り返しの意味

ターミナルでirbを実行することで、RubyのREPLが起動
終了はexit

・Rails console

ターミナルで実行すると、irb(main):001:0>というirbによるRubyコマンド待受状態になる
コードを変更したらreload!する。reload!コマンドを実行しないと再変更後のRubyコードは反映されない

・サーバの起動rails s
・エラーの発生
Mysql2::Error::ConnectionError

mysql2 の Gem からエラーは発せられていてり、データベースとの連携でエラーが出ていることを予想する
エラーを解消するために、新規でターミナルのタブを開き、sudo service mysql start で MySQL サーバを起動

Activerecord::NoDatabaseError

エラーメッセージから、'message-board_development' のデータベース名で作成すれば良さそうだと予想

・MySQL連携の設定ファイルの確認と変更

Rails のデータベースの接続設定を管理しているファイルは config/database.yml
この設定をRailsがサーバ起動時に読み込むことで、RailsとMySQLの接続が確立(連携)される

・MySQL接続時のユーザを変更

初期ではdefaultでrootに設定されているので、MySQLレッスンで作成したdbuserに変更
config/database.yml の16・17行目あたりにある username と password の設定を以下のとおりに変更し、ファイルを保存

username: dbuser
password: dbpass

・データベースの作成

rails db:create
👇

Created database 'message-board_development'
Created database 'message-board_test'

上記のデータベースが作成され、エラーが解決

・サーバを起動してデータベースの接続を確認

rails s

・Model

リソースであり操作対象。永久保存されるデータのためデータベースと密接に関係している。
はじめに作成するアプリケーションは、どんなデータを扱うのかを決める。

・Modelwo作成する

rails g model Message content:string

「メッセージのテーブル設計」
・マイグレーションファイル

Railsではマイグレーションファイルという、テーブル管理ファイルによってデータベースのテーブルを管理・実行する
主に、テーブル作成・削除、カラム追加・削除に関することがファイル内に記述される

Railsでテーブルの設定を変更したいときは、マイグレーションファイル作成、Railsからマイグレーション実行をする

def change ... end内にテーブル操作が書かれる

・マイグレーションの実行

マイグレーションファイルの作成だけでは実行されない
rails db:migrateで実行
※マイグレーション実行後は、このファイルを修正してもテーブルの変更はできない!
変更を加える時は、rails g migrationによって追加のマイグレーションファイルをさらに生成する

・マイグレーションの確認
MySQL ログイン
$ sudo mysql -u root

データベースの選択
mysql> use message-board_development

テーブル一覧確認(messagesテーブルが作成されているか確認)
mysql> show tables;

テーブル設計の確認
mysql> describe messages;
・モデルクラスの作成

マイグレーションでmodels/messages.rbも作成される
ActiveRecord::Base → ApplicationRecord という順番でクラスを継承した Message モデルには、それらの機能が全て継承されており、Message クラスにコードが無くてもモデル操作できる

ActiveRecord:

Railsという大きく統合されたライブラリ群の中の1つで、Model全般の操作を担うライブラリ
Railsアプリとのデータベース連携を担う
ActiveRecordを介する事で、ほとんどSQLを書かず、Rubyの文法でレコードを操作可能になる

・Modelで使用するCRUDメソッド一覧

all:全レコード取得
new:新規レコードの為のモデルインスタンス作成
find:idを指定して検索
find_by:id以外でも指定して検索
where:検索条件を文字列、配列、ハッシュのいずれかの方法で与えられる
first:最初のレコードを1件だけ取得する
save:レコードの作成
update,save:データの更新
destroy:データ削除

モデル名::メソッド名やモデルのインスタンス.メソッド名で使用

これらのRubyメソッドを使うことで、Rubyコードが自動的にSQLに変換されて実行される
ORM(Object-relational mapping):オブジェクト指向プログラミング言語コードでデータベースを操作できる技法

・Rails consoleでモデルのCRUD操作

rails console前に必ずSQLサーバ起動確認sudo service mysql status

・モデルの一覧を確認
Messages.all

・モデルのインスタンスを作成
message = Message.new(content: "test")

・モデルのインスタンスに値を代入
message.content = "hello"

・モデルのインスタンスをデータベースへ保存(Create) 
message.save

・モデルのインスタンスの取得(Read)

all:複数のレコードを取得するメソッドで、レコード全体を取得
First:最初のレコードのインスタンスを返す
find:idから単一のレコードを検索し返す
find_by:id以外でも単純な条件で検索可能
Where:条件指定してレコードを検索

・レコードの更新(Update)
findなどでレコードを取得、インスタンスに対して値を再代入、Saveするのが通常

・レコードの削除(Delete)
destroy:削除

・RouterとControllerとViewの開発概要
  1. Router:URLのルーティングを一元管理している
    config/routes.rbの1ファイルで、ルーティングを全て把握できる

  2. Controller:ユーザから送信されてきたHTTPリクエストの処理を担当
    HTTPリクエストはRouterからControllerの1つのメソッドに割り当てられる
    Routerと対応するControllerのメソッドをアクションと呼ぶ

  3. View:最終的にHTTPレスポンスとして返すWebページ

・RouterとControllerとViewの開発の流れ

どんな機能を作るか考え、実装すべき機能が挙がると、
1.ルーティングを決める
2.Controllerのメソッドを決める
3.Viewの名前を決める

「Router」

・リソースに対するCRUDの為の4つのルーティング

Rails.application.routes.draw do
  get 'messages/:id', to: 'messages#show'
  post 'messages', to: 'messages#create'
  put 'messages/:id', to: 'messages#update'
  delete 'messages/:id', to: 'messages#destroy'
end

:idはURLにidを入れる
POSTの場合だけidは不要。新規作成のためidはまだ用意されていない

・CRUDのための残り3つの補助ページ

詳細ページ(show)にアクセスするには、一覧ページ(index)が必要
get 'messages/:id', to: 'messages#show'
この詳細ページにアクセスするには、まずリソースの一覧ページがないと、個々のリソースページである詳細ページへ辿り着けない
👉一覧ページ(index)を付け加える
get 'messages', to: 'messages#index'

・保存アクション(create)にデータを送るには、新規作成用フォームページ(new)が必要
get 'messages/new', to: 'messages#new'

・更新アクション(update)にデータを送るには、更新用のフォームページ(edit)が必要
get 'messages/:id/edit', to: 'messages#edit'

・削除アクション(delete)はボタンがあればOK
どこかのページに削除ボタンが設置してあれば、削除ページは不要

・7つの基本ルーティングの省略形
Rails.application.routes.draw do
  # CRUD
  get 'messages/:id', to: 'messages#show'
  post 'messages', to: 'messages#create'
  put 'messages/:id', to: 'messages#update'
  delete 'messages/:id', to: 'messages#destroy'

  # index: show の補助ページ
  get 'messages', to: 'messages#index'

  # new: 新規作成用のフォームページ
  get 'messages/new', to: 'messages#new'

  # edit: 更新用のフォームページ
  get 'messages/:id/edit', to: 'messages#edit'
end

👇

Rails.application.routes.draw do
  resources :messages
end

これでさっきのルーティングと全く同じ意味になる。
indexやshowという命名をした理由は、resourcesで生成されるルーティングがそのように決まっているから

・Routerの完成
トップページにアクセスした時のルーティングをMessagesControllerのindexアクションに設定する。
indexアクションは、トップページ「/」と「/messages」にアクセスした両方で同じルーティングが設定されたことになる

Rails.application.routes.draw do
  root to: 'messages#index'

  resources :messages
end

・Routerの確認
routes.rbで少し込み入ったコーティングをした場合、rails routesで現状のルーティングを確認できる

resources :messagesで生成される7つのルーティングを『RESETfulなルーティングと呼ぶ』

RESETfulと言われたら、7つの基本アクション(index,show,new,create,edit,update,destroy)を思い出すように

●ControllerとView

・Controllerの作成
rails g controller コントローラ名(モデルの複数形)
Modelと同様に、継承によってControllerとしての基本機能が提供される

・ControllerをRESETfulなルーティングに対応させる
routes.rbで設定したルーティングに対応したアクションをmessages_controller.rbに追加

Controller内のルーティングと同じ名前のメソッド名として定義

・7つのアクションに対応したViewファイルの作成
GETメソッドで指定されたルーティングのみ
GET以外はリソースの具体的な操作の為

index.html.erb のように .erb だけでなく、.html と入れているのは、 ERB ファイルが HTML ファイルへと変換されることを Rails に対して明示するため

・共通部の書き出し
HTMLを書く時に必ず共通部分が出てくる
<!doctype html>やhead内要素
application.html.erbにまとめる!
body要素内の<%= yield %>に埋め込まれるページが切り替わる
👉<%= yield %>にindex.html.erbなどの内容が代入される

・7つのルーティングに対するレスポンスの実装
controllerのindexアクション:Messageモデルのレコード一覧表示

def index
    @messages = Message.all
end

viewの作成ほか・・・

link_to 表示文字列, リンク先
<%= link_to message.id,message %>
message のように Model のインスタンス(レコード)を渡すと、自動的にそのインスタンスの show アクションへとリンクされる

省略せずに書くと message_path(message) となり、リンク先 にこう記述しても正常に動作する
message も message_path(message) もどちらも最終的に /messages/1 など/messages/:id の形の URL を生成しているだけ

【リンク生成の為のメソッド】
Prefixとしてmessages,new_messagesなどが載せられている
ルーティングを設定すると、自動的にリンク生成の為のメソッドも定義される

(Prefix + _path)となる

:idが必要なものはインスタンスを特定する必要があるので、引数として@messageなどのインスタンスが必要
<%= link_to message.id, message_path(@message) %>

・View

ERBにフォームを設置
form_withを使用して生成

<h1>メッセージ新規作成ページ</h1>

<%= form_with(model: @message, local: true) do |f| %>
  <%= f.label :content, 'メッセージ' %>
  <%= f.text_field :content %>

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

<%= link_to '一覧に戻る', messages_path %>

form_withでフォーム開始、endで終了
form_with(model: @message)のように、Controllerのnewアクションで用意した@messageを使用してフォームを作成する事を明示する

(local: true)抜かすと画面推移しない通信が発生
今回はサイト内での遷移であること、ならびに画面遷移を伴う同期通信のみで構わないため local: true をつける

f.label,f.text_fieldでカラムを指定し、@messageの中のどのカラムに対する入力欄なのかを明示
f.submitで送信ボタンを生成

<%= link_to '新規メッセージの投稿', new_message_path %> を追加して、 index から new へのリンクを作成

  def create
    @message = Message.new(message_params)

    if @message.save
      flash[:success] = 'Message が正常に投稿されました'
      redirect_to @message
    else
      flash.now[:danger] = 'Message が投稿されませんでした'
      render :new
    end
  end

  def edit
  end

  def update
  end

  def destroy
  end

  private

  # Strong Parameter
  def message_params
    params.require(:message).permit(:content)
  end

コード下部 privateは、それ以降に定義されたメソッドがアクションではなく、クラス内でのみ使用する事を明示
def message_params が【Strong Parameter】
ちゃんと必要なパラメータを把握し、送信されてきたデータを精査(フィルタリング)しようということ
今回は:content以外のデータはフィルタにかけて捨てるようにしている

params.require(:message)でMessageモデルのフォームから得られるデータに関するものと明示し、.permit(:content)で必要なカラムだけを選択している

コード上部 @message = Message.new(message_params)で、Messageインスタンス生成時に、Strong parameterが使用されている

・redirect_toとrenderの違い
redirect_to:強制的に移動させる。createアクション実行→showアクション実行後、show.html.erbが呼ばれる
render:単にmessage/new.html.erbを表示するだけ(アクションは実行しない)

・flashとflash.nowの違い
redirect_toの前ならflash。HTTPリクエストを発生させるため、flash.nowだと内容を保存できず消えてしまう。
renderの前ならflash.now。HTTPリクエストを発生させないため消えない。

・flash表示ファイルの作成

view/layouts/_flash_messages.html.erb
<% flash.each do |message_type, message| %>
  <div><%= message %></div>
<% end %>

全てのviewで表示させたいため、application.html.erbでrenderする
(renderと書かれた場所に_flash_messages.html.erb の記述内容が埋め込まれる)

名前が_から始まるファイルを作成し、Viewの一部を抜き出して記述したものを『パーシャル』と呼ぶ

flashに代入されたメッセージを1つ1つ取り出し、全表示する。flashはハッシュである為、|key, value|のペアで取り出される。
今回は|message_type, message|という変数名を用いている。

views/layouts/application.html.erb
<body>
    <div class="container">
      <%= render 'layouts/flash_messages' %>

      <%= yield %>
    </div>
</body>

●messages#edit
既存のメッセージレコードを編集するので、idでメッセージレコードを検索する。(params[:id])

destroyアクションのredirect_to messages_url
今までprefix_pathだったが、リダイレクトの場合だけは上記で↑
messages_urlはPrefixがmessagesのためindexへリダイレクトされる
リダイレクトの時だけ_urlを使用する

show.html.erb
<%= link_to 'このメッセージを削除する', @message, method: :delete, data: { confirm: '本当に削除してよろしいですか?' } %>

method: :delete =DELETEメソッドを送信するのを明示
data: { confirm: ... } =javaScript

【bootstrapの適用】
・link_toにクラスを指定する
class "..."

・bootstrapのページネーション
コマンドでBootstrap用のkaminariのviewを生成
rails g kaminari:views bootstrap4

ページネーションに手を加える場合、viws/kaminariフォルダ内のファイルを編集

・show
showのp要素をテーブルに

<table>
  <thead>  table header
    <tr>   table rou(行)
      <td>  table data
...

一覧に戻るリンクを削除。navbarがあるため、タイトルクリックでindexに戻る為

・new
フォームにform-groupとform-controlのclass属性を付与

グリッドシステム
横長のテキスト入力欄をグリッドシステムで横半分に
フォームをrowとcol-6のdiv要素で囲む→6/12で半分

new.html一覧に戻るリンク削除

・edit
フォームはパーシャルで更新済
一覧に戻るリンク削除

まとめ

ModelはControllerによって必要なものが取得され、Viewに流れて表示される。ユーザのHTTPリクエストをRouterが解析し、リクエストに沿って適切なModelをユーザに表示するのがWebアプリケーション。
Modelはデータベースが無いと保存できない。データベースが用意される事で、Modelのインスタンスをレコードとして保存できるようになる。

【エラーのデバック】

エラー画面には以下の情報が含まれる
エラータイトル:例外クラスの名前と、発生場所
エラーが起きたファイル名:ファイルのパスと行番号
エラー詳細:エラーメッセージ
エラーが起きた行:強調表示される
トレース状況:エラーが起きたメソッドの呼び出し状況を出力
リクエスト情報:Railsサーバに送信したリクエスト
パラメータ:必要なパラメータが含まれているか、間違っていないか
レスポンス情報:Railsサーバーがどんなレスポンスを返したか

・エラーの修正手順
1.エラーの概要を理解する
タイトルと詳細を読んで概要を理解する
よくあるエラー👇
「NoMethodError in ...」
undefined method (a)for(b)
bにaというメソッドが存在しない。定義されていない、bに正しいデータが入っていない場合が多い
bがnil:NilClassの場合、エラーが起きた場所より前で正しくデータをセットできているか確認

「ActiveRecord::RecordNotFound in ...」
Coludn't find a with b
bの条件を満たすaが見つからない。ユーザIDを指定したけど、DB上にデータが存在しないなど。

「routingError」
No route matches [a] "b"
bのURLへのaメソッドのリクエストを受け取ったが、対応するルーティング設定がない
rails routesコマンドの結果や、routes.rbの内容を確認する

「Missing Template」
コントローラのアクションに対応するビューが存在しない
erbファイルが存在し、ファイルパスが正しい事を確認

「Syntax Error」
プログラムの文法エラー

・エラー発生部分を特定する

・ソースコードを修正する

Railsのデバックツール

pry-byebug Gemfileの追加
gem 'pry-byebug', group: :deveropment
bundle install
使い方
ソースコードの途中で、Railsアプリケーションの実行を一時的に止められる。実行を止めたい部分に「binding.pry」という1行を追加

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