Ruby on Rails 備忘録

「Ruby on Rails」を触ってみます。
今回はほとんどドットインストールkindleUnlimitedで学んだことの
備忘録みたいな感じです。

目次

アプリケーションの作成

1
rails new [アプリケーション名]

アプリケーションの実行

1
rails s

scaffold でのテーブル設定と作成

1
2
3
rails g scaffold [モデル名] [カラム名]:[データベース型]...
# データベース名は規約上は単数系の単語
rails db:migrate

モデルを作成し、テーブルを作成

1
2
3
rails g model [モデル名] [カラム名]:[データベース型]...
# モデル名は規約上は単数形の単語
rails db:migrate

データ作成(コマンドで)

1
2
3
4
5
6
7
8
9
# インタプリタの起動
rails c
# 作成と保存を別で行う場合
[変数A]=[モデル名].new([カラム名]:[データ],...)
[変数A].save

#即時反映
[変数A]=[モデル名].create([カラム名]:[データ],...)

データベースの中身を操作する。

1
2
3
4
5
6
7
8
9
# デフォルトのデータベースに接続する。
rails db
# テーブル一覧を見る
.table

# SQL文でデータ操作する

# 終了する
.exit

コントローラを作る

作成

1
rails g controller [コントローラ名]

コントローラ名は操作対象のモデルの複数形にする。が、必須ではない。
[アプリケーションルート]\app\controllers[コントローラ名]_controller.rb、
[アプリケーションルート]\app\views[コントローラ名]が作成される

編集

[コントローラ名]_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# コマンド実行後
class [コントローラ名]Controller < ApplicationController
end

# データをすべて取り出す関数(アクションとも)を作成する場合
class [コントローラ名]Controller < ApplicationController
def index
@data = [モデル名].all
# この場合、特別設定しなければ、[アプリケーションルート]\app\views\[コントローラ名]\index.html.erbが呼び出される
# 明示的に呼び出すビューを選ぶ場合
render 'index'
# もちろんindex関数の中でindexではないビューも呼び出せる。
render 'foo'

# jsonで返したいときは以下のようにする。
render :json => @data
end
end

ルーティングを作る

[アプリケーションルート]\config\routes.rb を編集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Rails.application.routes.draw do
# 一通り必要一般的なルーティングを作ってくれる
# scaffoldでテーブル作成すると、resourcesを使用してルーティングも記述処理される
resources :[コントローラ名]

# 個別にルーティングを定義する。
[リクエストメソッド] 'アクセスされるパス',to: '[コントローラ名]#[関数(アクション)名]'
# 例
get 'data', to: 'data#index'

# ルートパスを変更する。
# たとえばhttp://localhost:4444/でrailsのウェルカムページではないものを表示できるようになる。
root 'data#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

end

記述したルーティングを確認するときは

1
rails routes

ビューを作る

[アプリケーションルート]\app\views[コントローラ名][任意の名前].html.erb を作成する。

1
2
3
4
5
6
<h2>Posts</h2>
<ul>
<% [コントローラで定義したインスタンス変数].each do|data|%>
<li><%= data.name%></li>
<% end %>
</ul>

レイアウトを編集する

[アプリケーションルート]\app\views\layouts[レイアウト名].html.erb を編集する。
<%= yield %>の中に各コントローラで呼び出したビュー内容が展開される。

レイアウトを選ぶ

使用するレイアウトを指定することができる。

1
2
3
4
5
6
7
8
9
10
11
12
class AController < ApplicationController
layout "layout1"
# index関数ではコントローラで使用を宣言した
# [アプリケーションルート]\app\views\layouts\layout1.html.erbが使用される。
def index
end
# show関数では関数内で使用を宣言した
# [アプリケーションルート]\app\views\layouts\layout2.html.erbが使用される。
def show
render :show, layout: "layout2"
end
end

リンクを貼る

link_to ヘルパーを使ってビューの中で以下の記述でリンクを貼る

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%= link_to [リンクテキスト], "[リンク先]url" %>

# プレフィックスの使用例
<% @datas.each do|data|%>
#できる
<li><%= link_to data.title, data_path(data) %></li>

#できる
<li><%= link_to data.title, data %></li>

#できないみたい リンクがfoo.[データのID]になってしまう。
<li><%= link_to data.title, foo_path(data) %></li>

#できる
<li><%= link_to data.title, '/foo/'+data.id.to_s %></li>
<% end %>

foo_path(data)はリンクがたとえば/foo.1になってしまうので、使えなかった

画像を貼る

ビューで image ヘルパーを使用して img タグを使用する

1
2
3
4
5
6
7
8
9
# [アプリケーションルート]\app\assets\images\a.jpgを表示する
<%= image_tag 'a.jpg' %>

# class1をclassに割り当てる
<%= image_tag 'a.jpg', class: class1 %>

imgタグをリンクにする。
<%= link_to image_tag( 'a.jpg'),[リンク先URL] %>

オブジェクトと結びついたフォームを作る

コントローラに関数を用意

1
2
3
def new
@post = Post.new
end

ビューで form_for ヘルパーを使う

new.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<h2>Posts NEW</h2>
<%= form_for @post ,url:{action:"create"} do|f|%>
<p>
<%= f.text_field :title,placeholder:'placeholder1' %>
</p>
<p>
<%= f.text_area :body,placeholder:'placeholder2',value:'value' %>
</p>
<p>
<%= f.submit 'POST' %>
</p>
<% end %>

url:{action:”[アクション名]”}のアクション名の部分に
rails routes で確認できる Controller#Action の項目を割り当てる。
html への変換後に、URL Pattern に変換される。

ヘルパーから生成された html は以下のようになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<h2>Posts NEW</h2>
<form
class="new_post"
id="new_post"
action="/posts"
accept-charset="UTF-8"
method="post"
>
<input name="utf8" type="hidden" value="&#x2713;" /><input
type="hidden"
name="authenticity_token"
value="/4V2EYdAOgyFi65+RjeHYww69LUC8dgkMsmn8jznXmEggGHLHNdbfhGe2xTZmONbZh85nNhLrQb+SbSEdUW2gw=="
/>
<p>
<input
placeholder="placeholder1"
type="text"
name="post[title]"
id="post_title"
/>
</p>
<p>
<textarea placeholder="placeholder2" name="post[body]" id="post_body">
value</textarea
>
</p>
<p>
<input type="submit" name="commit" value="POST" data-disable-with="POST" />
</p>
</form>

フォームの入力を受け付ける

[モデル名]_contriller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def create
# httpリクエストの中身をhttpレスポンスとしてそのまま返す
render plain:params[:[モデル名]].inspect
# httpリクエストの中身をコマンドラインに出力する
puts params[:[モデル名]]

# params[:post]でデータを受け取れるが[データモデル].newと絡めると
# ActiveModel::ForbiddenAttributesErrorというエラーになる。
@post = Post.new(params[:[モデル名]])
# ストロングパラメータで検証する。
# @post = Post.new(params.require(:[モデル名]).permit(:[カラム名],:[カラム名]))
# ストロングパラメータを使うと以下のようになる。
@post = Post.new(params.require(:post).permit(:title,:body))
# データを保存
@post.save
# レスポンスをリダイレクト
redirect_to posts_path
end

バリデーションを作る

[アプリケーションルート]\app\models\モデル名.rb

1
2
3
4
class [モデル名] < ApplicationRecord
validates :title ,presence:true,length:{minimum:5,message:'SHORT!!'}
validates :body ,presence:true
end

presence は、空ではない項目つまり必須項目の指定。
length は文字列長の設定,上では minimum を使用して短さで指定しているが、
maximum(最大長),in(範囲),is(文字列長一致)などもある。

バリデーション結果で動作を振り分ける

save メソッドが返り値を持っていて、
バリデーションの結果を errors.inspect に格納している。

[モデル名]_contriller.rb
1
2
3
4
5
6
7
8
9
10
def create
@post = Post.new(params.require(:post).permit(:title,:body))
if @post.save
#成功したのでリダイレクト
redirect_to posts_path
else
#失敗したのでエラー表示を返す。
render plain:@post.errors.inspect
end
end

バリデーションの結果がエラーのとき入力画面に返す場合

コントローラで、エラーのときに表示するビューを指定する。

[モデル名]_contriller.rb
1
2
3
4
5
6
7
8
9
def create
@post = Post.new(params.require(:post).permit(:title,:body))
if @post.save
redirect_to posts_path
else
#表示させるビューを指定する。
render 'new'
end
end

ビューで、エラー時のみ表示する項目を設定する
各部分はどこでもよい。

1
2
3
4
5
6

<% if @post.errors.messages[:title].any? %>
<span>
<%= @post.errors.messages[:title][0] %>
</span>
<% end %>

これでエラー発生時に表示される項目が定義でできる。

また、エラーの対象になった項目 input タグが、field_with_errors クラスが付与された div 要素に包まれる。
標準の css だと赤が込みされた。

値の更新

コントローラで edit、update アクションを定義

[モデル名]_contriller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def edit
# idを基準にデータを格納
@post = Post.find(params[:id])
end

def update
# idを基準にデータを更新
@post = Post.find(params[:id])
if @post.update(params.require(:post).permit(:title,:body))
#バリデーション結果がOKなので表示画面に遷移
render 'show'
else
#バリデーション結果がエラーなので再度編集
render 'edit'
end
end

編集画面を edit.html.erb に定義
:title、:body のようにすることで、格納されたデータを value に埋め込む

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h2>Posts EDIT</h2>
<%= form_for @post ,url:{action:"update"} do|f|%>
<p>
<%= f.text_field :title,placeholder:'placeholder1' %>
</p>
<p>
<%= f.text_area :body,placeholder:'placeholder2' %>
<% if @post.errors.messages[:title].any? %>
<span><% @post.errors.messages[:title][0] %></span>
<% end %>
</p>
<p>
<%= f.submit 'UPDATE' %>
</p>
<% end %>

以上でデータ更新画面の遷移が作成できた。

値の削除

コントローラで destroy アクションを定義

[モデル名]_contriller.rb
1
2
3
4
5
def destroy
@post = Post.find(params[:id])
@post.destroy
redirect_to root_path
end

どこかのビューで削除リンクを定義する。

1
<%= link_to 'DEL', method:delete post_path(post) data:{confirm:'DELETE OK?'}%>

edit 画面で現在の URL が/posts/6/edit のようなときボタンなら次のように作れた。

1
2
3
4
パターン1
<%= button_to "DELETE", post_path, {method: :delete} %>
パターン2
<%= button_to "DELETE", {controller: 'posts', action: 'destroy'}, method: :delete %>

この時、
<%= f.submit 'POST' %>と共存しようとしたら、失敗した。
update と delete を共存する場合の edit のビューは次のようになった。
<%= button_to 'UPDATE', {controller: 'posts', action: 'update'}, method: :patch %>に書き換えて次のようにする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<h2>Posts EDIT</h2>
<%= form_for @post ,url:{action:"update"}, method: :patch do|f|%>
<p>
<%= f.text_field :title,placeholder:'placeholder1' %>
</p>
<p>
<%= f.text_area :body,placeholder:'placeholder2' %>
<% if @post.errors.messages[:title].any? %>
<span><% @post.errors.messages[:title][0] %></span>
<% end %>
</p>
<p>
<%= button_to 'UPDATE', {controller: 'posts', action: 'update'}, method: :patch %>
<%= button_to "DELETE", {controller: 'posts', action: 'destroy'}, method: :delete %>
</p>
<% end %>

index 画面などであれば、それぞれの id を使用して次のようにできた。

1
2
3
4
5
<% @posts.each do|post|%>
<li>
<%= link_to post.title, post_path(post)%>
<%= button_to "DELETE", post_path(post), method: :delete %>
<% end %>

今回の記事ではデータの、CRUD(作成、読み出し、更新、削除)まで、できました。

長くなりすぎなので、続きは別記事にします。

以上