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
# インタプリタの起動
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
# コマンド実行後
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
# [アプリケーションルート]\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
<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(作成、読み出し、更新、削除)まで、できました。

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

以上