SlideShare a Scribd company logo
Rails Controller Fundamentals
— とっとるびー第31回 2018-09-24
— https://tottoruby.connpass.com/event/100646/
— @hamajyotan (SAKAGUCHI Takashi)
さきにお伝え
— ちょっとした Rails コードを動かしたりします. 以下
の状態が手元にあると, 一緒に試したりできます.
— Ruby 2.5.1 , Rails 5.2.1 で実施しますが, そこまで
厳密に合わせる必要はないです.
— gem sqlite3. (rails new で database を指定しない
ので既定で使っているだけであり, 行間読んで別
DB を指定できればそれで OK です)
自己紹介
— SAKAGUCHI Takashi
— Office UMMM LLC
— Ruby とか Rails とかがちょっとできるおじさんです
今日話すこと
— scaffold よくみてみようという件
— resource routing にこだわろうという件
— template inheritance 便利だよという件
scaffold よくみてみようという件
簡単なアプリを作りつつ
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
$ rails -v
Rails 5.2.1
$ rails new example --skip-active-storage
出力省略...
$ cd example/
$ ./bin/rails s
➡ http://localhost:3000
簡単なアプリを作りつつ
$ ./bin/rails scaffold message 
title body:text 
published:boolean
$ ./bin/rails db:migrate
➡ http://localhost:3000/
messages
resource(s) なルーティング
config/routes.rb
Rails.application.routes.draw do
resources :messages
end
$ rails routes
Prefix Verb URI Pattern Controller#Action
messages GET /messages(.:format) messages#index
POST /messages(.:format) messages#create
new_message GET /messages/new(.:format) messages#new
edit_message GET /messages/:id/edit(.:format) messages#edit
message GET /messages/:id(.:format) messages#show
PATCH /messages/:id(.:format) messages#update
PUT /messages/:id(.:format) messages#update
DELETE /messages/:id(.:format) messages#destroy
アクションとその意味
Action 意味
index 一覧表示(画面)
create 新規作成
new 新規作成(画面)
edit 編集(画面)
show 詳細表示(画面)
update 更新
destroy 削除
html 都合の new/edit はこのさい置いとく
Resource HTTP Method Action 意味
/messages GET index 一覧表示(画面)
/messages POST create 新規作成
/message/:id GET show 詳細表示(画面)
/message/:id PATCH/PUT update 更新
/message/:id DELETE destroy 削除
HTTP のメソッド
HTTP Method /messages /message/:id
GET index show
PUT/PATCH - update
DELETE - destroy
POST create -
HTTP のメソッド
HTTP Method 意図など 安全 冪等
GET リソースの取得 ! !
PUT/PATCH リソースの配置 !❓
DELETE リソースの削除 !❓
POST リソースの生成
GET
— リソースの取得. 常に安全で冪等.
— scaffold の実装だと, コレクションへの GET は常に
200 でメンバーへの GET はない場合 404 を返す.
def index
@messages = Message.all
end
def show
end
PUT/PATCH
— リソースの配置.
— scaffold の実装の場合存在しない場合は 404 を返す
が, 定義からすれば ID を明示した merge (insert or
update) とした方が適当かも.
def update
respond_to do |format|
if @message.update(message_params)
format.html { redirect_to @message, notice: 'Message was successfully updated.' }
format.json { render :show, status: :ok, location: @message }
else
format.html { render :edit }
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
DELETE
— リソースの削除.
— scaffold の実装の場合存在しない場合は 404 を返す
が, 定義からすれば存在しない場合は何もしないのが
適当かも.
def destroy
@message.destroy
respond_to do |format|
format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' }
format.json { head :no_content }
end
end
POST
— リソースの生成
— 「生成」としているのはコレクションリソースに対
する操作であるため.
def create
@message = Message.new(message_params)
respond_to do |format|
if @message.save
format.html { redirect_to @message, notice: 'Message was successfully created.' }
format.json { render :show, status: :created, location: @message }
else
format.html { render :new }
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
60行すこし
class MessagesController < ApplicationController
before_action :set_message, only: [:show, :edit, :update, :destroy]
def index
@messages = Message.all
end
def show; end
def new
@message = Message.new
end
def edit; end
def create
@message = Message.new(message_params)
respond_to do |format|
if @message.save
format.html { redirect_to @message, notice: 'Message was successfully created.' }
format.json { render :show, status: :created, location: @message }
else
format.html { render :new }
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @message.update(message_params)
format.html { redirect_to @message, notice: 'Message was successfully updated.' }
format.json { render :show, status: :ok, location: @message }
else
format.html { render :edit }
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
def destroy
@message.destroy
respond_to do |format|
format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_message
@message = Message.find(params[:id])
end
def message_params
params.require(:message).permit(:title, :body, :published)
end
end
resource routing にこだわろうという件
メッセージにお気に入りをつけたい
— って要件を考えてみる.
— 特定のメッセージに対してお気に入りにしたりそれ
を外したりできる
— 今回は「誰が」お気に入りをつけるのか? という情報
はサボる
— 本質でないので, 簡単に favorited:boolean の
フラグを Message モデルにつけるだけにしてる.
favorited フラグを用意する
$ ./bin/rails g migration AddFavoritedToMessages favorited:boolean
$ ./bin/rails db:migrate
どのようなアクションを準備すべきか?
resources :messages do
post :add_favorite, on: :member
post :remove_favorite, on: :member
end
$ ./bin/rails routes
Prefix Verb URI Pattern Controller#Action
add_favorite_message POST /messages/:id/add_favorite(.:format) messages#add_favorite
remove_favorite_message POST /messages/:id/remove_favorite(.:format) messages#remove_favorite
...
class MessagesController < ApplicationController
def add_favorite
end
def remove_favorite
end
...
➡ (´・ω・`)…
どのようなアクションを準備すべきか?
resources :messages do
put :favorite, on: :member
delete :favorite, on: :member
end
$ ./bin/rails routes
Prefix Verb URI Pattern Controller#Action
favorite_message PUT /messages/:id/favorite(.:format) messages#favorite
DELETE /messages/:id/favorite(.:format) messages#favorite
...
class MessagesController < ApplicationController
def favorite # favorite & unfavorite ?
end
...
➡ (´・ω・`)……
どのようなアクションを準備すべきか?
resources :messages do
put :favorite, on: :member, action: 'add_favorite'
delete :favorite, on: :member, action: 'remove_favorite'
end
$ ./bin/rails routes
Prefix Verb URI Pattern Controller#Action
favorite_message PUT /messages/:id/favorite(.:format) messages#add_favorite
DELETE /messages/:id/favorite(.:format) messages#remove_favorite
...
class MessagesController < ApplicationController
def add_favorite
end
def remote_favorite
end
...
➡ (´・ω・`)………
ルーティングの設計ガイドライン
— resource(s) で提供されるアクション以外を避ける
— index, show, new, create, edit, update, destroy のみ
— config/routes.rb で get とか post とかをな
るべく使わない.
ルーティングの設計ガイドライン
— 実現することから名詞を探し, 積極的にサブリソース
としてデザインする
— /messages/:message_id/favorite
ルーティングの設計ガイドライン
— 今回の例では /messages/:message_id/
favorite に対して PUT/DELETE で実現
— DELETE だからと言って, 実際に DB 上でデータを
削除する必要はない.
— URI のリソースに対し, DB での永続化方法は全
く別の話.
— DB構成変えるたびに URI構成変えないでしょ?
再考 - ルーティング
resources :messages do
resource :favorite, only: %i[update destroy], module: 'messages'
end
$ ./bin/rails routes
Prefix Verb URI Pattern Controller#Action
message_favorite PATCH /messages/:message_id/favorite(.:format) messages/favorites#update
PUT /messages/:message_id/favorite(.:format) messages/favorites#update
DELETE /messages/:message_id/favorite(.:format) messages/favorites#destroy
...
再考 - コントローラ
# app/controllers/messages/favorites_controller.rb
class < Messages::FavoritesController
before_action :set_message
def update
respond_to do |format|
if @message.update(favorited: true)
format.html { redirect_to @message, notice: 'Favorited.' }
else
format.html { redirect_to @message, alert: 'Favorite failed.' }
end
end
end
def destroy
respond_to do |format|
if @message.update(favorited: false)
format.html { redirect_to @message, notice: 'Unfavorited.' }
else
format.html { redirect_to @message, alert: 'Unfavorite failed.' }
end
end
end
private
def set_message
@message = Message.find(params[:message_id])
end
end
# (json 省略.)
template inheritance 便利だよという件
template inheritance #とは
— ビューはどのディレクトリ/ファイルを探索する?
— app/views/コントローラ名/アクション名.拡張子
みたいなところ?
— ➡ だいたいあってるけどもうひといき
— ➡
❓
template inheritance #とは
— ビューはどのディレクトリ/ファイルを探索する?
— app/views/コントローラ名/アクション名.拡張子
みたいなところ?
— ➡ だいたいあってるけどもうひといき
— ➡ コントローラの継承ツリーがヒントになっている
view template の探索順序
— コントローラの継承ツリー
— MessagesController
— < ApplicationController
— ➡ 以下の順に探索される
1. app/views/messages/*
2. app/views/application/*
view template の探索順序
— 例えば Messages のサブクラスの Foos を作ったら
— FoosController < MessagesController
— ➡ 以下の順に探索される
1. app/views/foos/*
2. app/views/messages/*
3. app/views/application/*
ちょっとためそう
$ mkdir app/views/application
$ mv app/views/messages/index.html.erb app/views/application/
➡ 場所移しても動く.
$ cp app/views/application/index.html.erb app/views/messages/index.html.erb
$ echo '<h2>ほげ</h2>' >> app/views/messages/index.html.erb
➡ messages/ が優先.
みんな ApplicationController を継承してるということは
— app/views/application/ は共通ビューテンプレ
ート置き場に使える.
— しかも, 場合によっては各々のコントローラで上書き
できる.
— これ知らずに app/views/shared/* とか作るより
Rails way かと.
たとえばこんなルーティング
— /messages - メッセージ一覧
— これに対して、 /messages/draft という URL を準
備する
— 基本的には /messages と同じ.
— ただし, published が false のデータでフィルタ
された状態とする.
/messages/draft をつくる - 1/4
app/controllers/messages_controller.rb
def index
- @messages = Message.all
+ @messages = message_scope
end
private
+ def message_scope
+ Message.all
+ end
+
def set_message
/messages/draft をつくる - 2/4
app/controllers/messages/
drafts_controller.rb
class Messages::DraftsController < MessagesController
private
def message_scope
Message.where(published: false)
end
end
/messages/draft をつくる - 3/4
config/routes.rb
Rails.application.routes.draw do
+ namespace :messages do
+ resources :drafts, only: %i[index]
+ end
resources :messages
end
/messages/draft をつくる - 4/4
config/routes.rb
Rails.application.routes.draw do
namespace :messages do
- resources :drafts, only: %i[index]
+ resources :drafts, only: %i[index], path: 'draft'
end
resources :messages
end
➡ 以上
❗
ビューの修正などはなし
まとめ
— scaffold の吐くコントローラは良いコード.
— routes にはなるべく resource(s) だけを記述.
— URIでデザインするリソースと DB永続化は別の話.
— template inheritance をうまく使おう.
— 共通のテンプレートは
app/views/application/ ディレクトリ

More Related Content

What's hot

Webサーバ勉強会 発表資料
Webサーバ勉強会 発表資料Webサーバ勉強会 発表資料
Webサーバ勉強会 発表資料
oranie Narut
 
Alfrescoのカスタムテーブルの使い方
Alfrescoのカスタムテーブルの使い方Alfrescoのカスタムテーブルの使い方
Alfrescoのカスタムテーブルの使い方
Jun Terashita
 
Flask勉強会その1
Flask勉強会その1Flask勉強会その1
Flask勉強会その1
Masato Kawamura
 
Rails3.1rc4を試してみた
Rails3.1rc4を試してみたRails3.1rc4を試してみた
Rails3.1rc4を試してみた
Takahiro Hidaka
 
Flyway使いたい
Flyway使いたいFlyway使いたい
Flyway使いたい
fourside
 
Erlang Web
Erlang WebErlang Web
Erlang Web
Ngoc Dao
 
Mysql casual talks vol4
Mysql casual talks vol4Mysql casual talks vol4
Mysql casual talks vol4
matsuo kenji
 
Fuel php osc tokyo2012
Fuel php osc tokyo2012Fuel php osc tokyo2012
Fuel php osc tokyo2012
Fumito Mizuno
 
Ruby on Rails Tutorial
Ruby on Rails TutorialRuby on Rails Tutorial
Ruby on Rails Tutorial
Ken Iiboshi
 
FuelPHPをさわってみて
FuelPHPをさわってみてFuelPHPをさわってみて
FuelPHPをさわってみて
Sotaro Omura
 
.htaccessによるリダイレクト徹底解説
.htaccessによるリダイレクト徹底解説.htaccessによるリダイレクト徹底解説
.htaccessによるリダイレクト徹底解説
Cherry Pie Web
 
FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1
Fumito Mizuno
 
10分でわかるFuelPHP @ 2011/12
10分でわかるFuelPHP @ 2011/1210分でわかるFuelPHP @ 2011/12
10分でわかるFuelPHP @ 2011/12
kenjis
 
Mixer2 で作るカスタムテンプレートエンジン #渋谷java
Mixer2 で作るカスタムテンプレートエンジン #渋谷javaMixer2 で作るカスタムテンプレートエンジン #渋谷java
Mixer2 で作るカスタムテンプレートエンジン #渋谷java
Jun Futagawa
 
10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
 10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya 10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
kenjis
 

What's hot (16)

Pyramid入門
Pyramid入門Pyramid入門
Pyramid入門
 
Webサーバ勉強会 発表資料
Webサーバ勉強会 発表資料Webサーバ勉強会 発表資料
Webサーバ勉強会 発表資料
 
Alfrescoのカスタムテーブルの使い方
Alfrescoのカスタムテーブルの使い方Alfrescoのカスタムテーブルの使い方
Alfrescoのカスタムテーブルの使い方
 
Flask勉強会その1
Flask勉強会その1Flask勉強会その1
Flask勉強会その1
 
Rails3.1rc4を試してみた
Rails3.1rc4を試してみたRails3.1rc4を試してみた
Rails3.1rc4を試してみた
 
Flyway使いたい
Flyway使いたいFlyway使いたい
Flyway使いたい
 
Erlang Web
Erlang WebErlang Web
Erlang Web
 
Mysql casual talks vol4
Mysql casual talks vol4Mysql casual talks vol4
Mysql casual talks vol4
 
Fuel php osc tokyo2012
Fuel php osc tokyo2012Fuel php osc tokyo2012
Fuel php osc tokyo2012
 
Ruby on Rails Tutorial
Ruby on Rails TutorialRuby on Rails Tutorial
Ruby on Rails Tutorial
 
FuelPHPをさわってみて
FuelPHPをさわってみてFuelPHPをさわってみて
FuelPHPをさわってみて
 
.htaccessによるリダイレクト徹底解説
.htaccessによるリダイレクト徹底解説.htaccessによるリダイレクト徹底解説
.htaccessによるリダイレクト徹底解説
 
FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1
 
10分でわかるFuelPHP @ 2011/12
10分でわかるFuelPHP @ 2011/1210分でわかるFuelPHP @ 2011/12
10分でわかるFuelPHP @ 2011/12
 
Mixer2 で作るカスタムテンプレートエンジン #渋谷java
Mixer2 で作るカスタムテンプレートエンジン #渋谷javaMixer2 で作るカスタムテンプレートエンジン #渋谷java
Mixer2 で作るカスタムテンプレートエンジン #渋谷java
 
10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
 10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya 10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
10分でわかるFuelPHP @ 2012/05 OSC2012 Nagoya
 

Similar to Rails Controller Fundamentals

Rails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd editionRails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd edition
Goh Matsumoto
 
第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)Masanori Machii
 
スマートフォン向けサービスにおけるサーバサイド設計入門
スマートフォン向けサービスにおけるサーバサイド設計入門スマートフォン向けサービスにおけるサーバサイド設計入門
スマートフォン向けサービスにおけるサーバサイド設計入門Hisashi HATAKEYAMA
 
Ruby on Rails3 Tutorial Chapter2
Ruby on Rails3 Tutorial Chapter2Ruby on Rails3 Tutorial Chapter2
Ruby on Rails3 Tutorial Chapter2Sea Mountain
 
Ruby で扱う LDAP のススメ
Ruby で扱う LDAP のススメRuby で扱う LDAP のススメ
Ruby で扱う LDAP のススメ
Kazuaki Takase
 
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発emasaka
 
Ruby on Rails Tutorial Chapter5-7
Ruby on Rails Tutorial Chapter5-7Ruby on Rails Tutorial Chapter5-7
Ruby on Rails Tutorial Chapter5-7
Sea Mountain
 
Web技術勉強会23回目
Web技術勉強会23回目Web技術勉強会23回目
Web技術勉強会23回目
龍一 田中
 
Rails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3editionRails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3editionSatomi Tsujita
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Setxibbar
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方linzhixing
 
Couch Db勉強会0623 by yssk22
Couch Db勉強会0623 by yssk22Couch Db勉強会0623 by yssk22
Couch Db勉強会0623 by yssk22
Yohei Sasaki
 
ASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おうASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おう
DevTakas
 
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作るEWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
Kiyoshi Sawada
 
徳島OSS勉強会第四回 シラサギハンズオン 0925
徳島OSS勉強会第四回 シラサギハンズオン 0925徳島OSS勉強会第四回 シラサギハンズオン 0925
徳島OSS勉強会第四回 シラサギハンズオン 0925
Yu Ito
 
Ruby on Rails3 Tutorial Chapter3
Ruby on Rails3 Tutorial Chapter3Ruby on Rails3 Tutorial Chapter3
Ruby on Rails3 Tutorial Chapter3Sea Mountain
 
「html5 boilerplate」から考える、これからのマークアップ
「html5 boilerplate」から考える、これからのマークアップ「html5 boilerplate」から考える、これからのマークアップ
「html5 boilerplate」から考える、これからのマークアップ
Yasuhito Yabe
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogrammingMasanori Kado
 
Rails基礎講座 part.2
Rails基礎講座 part.2Rails基礎講座 part.2
Rails基礎講座 part.2
Jun Yokoyama
 

Similar to Rails Controller Fundamentals (20)

Rails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd editionRails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd edition
 
第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)第2回品川Redmine勉強会(日本語全文検索)
第2回品川Redmine勉強会(日本語全文検索)
 
スマートフォン向けサービスにおけるサーバサイド設計入門
スマートフォン向けサービスにおけるサーバサイド設計入門スマートフォン向けサービスにおけるサーバサイド設計入門
スマートフォン向けサービスにおけるサーバサイド設計入門
 
Ruby on Rails3 Tutorial Chapter2
Ruby on Rails3 Tutorial Chapter2Ruby on Rails3 Tutorial Chapter2
Ruby on Rails3 Tutorial Chapter2
 
scala-kaigi1-sbt
scala-kaigi1-sbtscala-kaigi1-sbt
scala-kaigi1-sbt
 
Ruby で扱う LDAP のススメ
Ruby で扱う LDAP のススメRuby で扱う LDAP のススメ
Ruby で扱う LDAP のススメ
 
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発
ゲットーの斜め上をゆくWebアプリケーションフレームワークの開発
 
Ruby on Rails Tutorial Chapter5-7
Ruby on Rails Tutorial Chapter5-7Ruby on Rails Tutorial Chapter5-7
Ruby on Rails Tutorial Chapter5-7
 
Web技術勉強会23回目
Web技術勉強会23回目Web技術勉強会23回目
Web技術勉強会23回目
 
Rails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3editionRails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3edition
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Set
 
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
Alfresco勉強会20120829: やさしいShareダッシュレットの作り方
 
Couch Db勉強会0623 by yssk22
Couch Db勉強会0623 by yssk22Couch Db勉強会0623 by yssk22
Couch Db勉強会0623 by yssk22
 
ASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おうASP.NET Core WebAPIでODataを使おう
ASP.NET Core WebAPIでODataを使おう
 
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作るEWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る
 
徳島OSS勉強会第四回 シラサギハンズオン 0925
徳島OSS勉強会第四回 シラサギハンズオン 0925徳島OSS勉強会第四回 シラサギハンズオン 0925
徳島OSS勉強会第四回 シラサギハンズオン 0925
 
Ruby on Rails3 Tutorial Chapter3
Ruby on Rails3 Tutorial Chapter3Ruby on Rails3 Tutorial Chapter3
Ruby on Rails3 Tutorial Chapter3
 
「html5 boilerplate」から考える、これからのマークアップ
「html5 boilerplate」から考える、これからのマークアップ「html5 boilerplate」から考える、これからのマークアップ
「html5 boilerplate」から考える、これからのマークアップ
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
Rails基礎講座 part.2
Rails基礎講座 part.2Rails基礎講座 part.2
Rails基礎講座 part.2
 

Recently uploaded

論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
Toru Tamaki
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
Matsushita Laboratory
 
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援しますキンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
Takayuki Nakayama
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
CRI Japan, Inc.
 
Generating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language ModelsGenerating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language Models
harmonylab
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
chiefujita1
 
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
Toru Tamaki
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
t m
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
Matsushita Laboratory
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
0207sukipio
 

Recently uploaded (10)

論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
 
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援しますキンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
キンドリル ネットワークアセスメントサービスご紹介 今のネットワーク環境は大丈夫? 調査〜対策までご支援します
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
 
Generating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language ModelsGenerating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language Models
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
 
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
論文紹介:Deep Learning-Based Human Pose Estimation: A Survey
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
 

Rails Controller Fundamentals

  • 1. Rails Controller Fundamentals — とっとるびー第31回 2018-09-24 — https://tottoruby.connpass.com/event/100646/ — @hamajyotan (SAKAGUCHI Takashi)
  • 2. さきにお伝え — ちょっとした Rails コードを動かしたりします. 以下 の状態が手元にあると, 一緒に試したりできます. — Ruby 2.5.1 , Rails 5.2.1 で実施しますが, そこまで 厳密に合わせる必要はないです. — gem sqlite3. (rails new で database を指定しない ので既定で使っているだけであり, 行間読んで別 DB を指定できればそれで OK です)
  • 3. 自己紹介 — SAKAGUCHI Takashi — Office UMMM LLC — Ruby とか Rails とかがちょっとできるおじさんです
  • 4. 今日話すこと — scaffold よくみてみようという件 — resource routing にこだわろうという件 — template inheritance 便利だよという件
  • 6. 簡単なアプリを作りつつ $ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] $ rails -v Rails 5.2.1 $ rails new example --skip-active-storage 出力省略... $ cd example/ $ ./bin/rails s ➡ http://localhost:3000
  • 7. 簡単なアプリを作りつつ $ ./bin/rails scaffold message title body:text published:boolean $ ./bin/rails db:migrate ➡ http://localhost:3000/ messages
  • 8. resource(s) なルーティング config/routes.rb Rails.application.routes.draw do resources :messages end $ rails routes Prefix Verb URI Pattern Controller#Action messages GET /messages(.:format) messages#index POST /messages(.:format) messages#create new_message GET /messages/new(.:format) messages#new edit_message GET /messages/:id/edit(.:format) messages#edit message GET /messages/:id(.:format) messages#show PATCH /messages/:id(.:format) messages#update PUT /messages/:id(.:format) messages#update DELETE /messages/:id(.:format) messages#destroy
  • 9. アクションとその意味 Action 意味 index 一覧表示(画面) create 新規作成 new 新規作成(画面) edit 編集(画面) show 詳細表示(画面) update 更新 destroy 削除
  • 10. html 都合の new/edit はこのさい置いとく Resource HTTP Method Action 意味 /messages GET index 一覧表示(画面) /messages POST create 新規作成 /message/:id GET show 詳細表示(画面) /message/:id PATCH/PUT update 更新 /message/:id DELETE destroy 削除
  • 11. HTTP のメソッド HTTP Method /messages /message/:id GET index show PUT/PATCH - update DELETE - destroy POST create -
  • 12. HTTP のメソッド HTTP Method 意図など 安全 冪等 GET リソースの取得 ! ! PUT/PATCH リソースの配置 !❓ DELETE リソースの削除 !❓ POST リソースの生成
  • 13. GET — リソースの取得. 常に安全で冪等. — scaffold の実装だと, コレクションへの GET は常に 200 でメンバーへの GET はない場合 404 を返す. def index @messages = Message.all end def show end
  • 14. PUT/PATCH — リソースの配置. — scaffold の実装の場合存在しない場合は 404 を返す が, 定義からすれば ID を明示した merge (insert or update) とした方が適当かも. def update respond_to do |format| if @message.update(message_params) format.html { redirect_to @message, notice: 'Message was successfully updated.' } format.json { render :show, status: :ok, location: @message } else format.html { render :edit } format.json { render json: @message.errors, status: :unprocessable_entity } end end end
  • 15. DELETE — リソースの削除. — scaffold の実装の場合存在しない場合は 404 を返す が, 定義からすれば存在しない場合は何もしないのが 適当かも. def destroy @message.destroy respond_to do |format| format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' } format.json { head :no_content } end end
  • 16. POST — リソースの生成 — 「生成」としているのはコレクションリソースに対 する操作であるため. def create @message = Message.new(message_params) respond_to do |format| if @message.save format.html { redirect_to @message, notice: 'Message was successfully created.' } format.json { render :show, status: :created, location: @message } else format.html { render :new } format.json { render json: @message.errors, status: :unprocessable_entity } end end end
  • 17. 60行すこし class MessagesController < ApplicationController before_action :set_message, only: [:show, :edit, :update, :destroy] def index @messages = Message.all end def show; end def new @message = Message.new end def edit; end def create @message = Message.new(message_params) respond_to do |format| if @message.save format.html { redirect_to @message, notice: 'Message was successfully created.' } format.json { render :show, status: :created, location: @message } else format.html { render :new } format.json { render json: @message.errors, status: :unprocessable_entity } end end end def update respond_to do |format| if @message.update(message_params) format.html { redirect_to @message, notice: 'Message was successfully updated.' } format.json { render :show, status: :ok, location: @message } else format.html { render :edit } format.json { render json: @message.errors, status: :unprocessable_entity } end end end def destroy @message.destroy respond_to do |format| format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' } format.json { head :no_content } end end private def set_message @message = Message.find(params[:id]) end def message_params params.require(:message).permit(:title, :body, :published) end end
  • 19. メッセージにお気に入りをつけたい — って要件を考えてみる. — 特定のメッセージに対してお気に入りにしたりそれ を外したりできる — 今回は「誰が」お気に入りをつけるのか? という情報 はサボる — 本質でないので, 簡単に favorited:boolean の フラグを Message モデルにつけるだけにしてる.
  • 20. favorited フラグを用意する $ ./bin/rails g migration AddFavoritedToMessages favorited:boolean $ ./bin/rails db:migrate
  • 21. どのようなアクションを準備すべきか? resources :messages do post :add_favorite, on: :member post :remove_favorite, on: :member end $ ./bin/rails routes Prefix Verb URI Pattern Controller#Action add_favorite_message POST /messages/:id/add_favorite(.:format) messages#add_favorite remove_favorite_message POST /messages/:id/remove_favorite(.:format) messages#remove_favorite ... class MessagesController < ApplicationController def add_favorite end def remove_favorite end ... ➡ (´・ω・`)…
  • 22. どのようなアクションを準備すべきか? resources :messages do put :favorite, on: :member delete :favorite, on: :member end $ ./bin/rails routes Prefix Verb URI Pattern Controller#Action favorite_message PUT /messages/:id/favorite(.:format) messages#favorite DELETE /messages/:id/favorite(.:format) messages#favorite ... class MessagesController < ApplicationController def favorite # favorite & unfavorite ? end ... ➡ (´・ω・`)……
  • 23. どのようなアクションを準備すべきか? resources :messages do put :favorite, on: :member, action: 'add_favorite' delete :favorite, on: :member, action: 'remove_favorite' end $ ./bin/rails routes Prefix Verb URI Pattern Controller#Action favorite_message PUT /messages/:id/favorite(.:format) messages#add_favorite DELETE /messages/:id/favorite(.:format) messages#remove_favorite ... class MessagesController < ApplicationController def add_favorite end def remote_favorite end ... ➡ (´・ω・`)………
  • 24. ルーティングの設計ガイドライン — resource(s) で提供されるアクション以外を避ける — index, show, new, create, edit, update, destroy のみ — config/routes.rb で get とか post とかをな るべく使わない.
  • 26. ルーティングの設計ガイドライン — 今回の例では /messages/:message_id/ favorite に対して PUT/DELETE で実現 — DELETE だからと言って, 実際に DB 上でデータを 削除する必要はない. — URI のリソースに対し, DB での永続化方法は全 く別の話. — DB構成変えるたびに URI構成変えないでしょ?
  • 27. 再考 - ルーティング resources :messages do resource :favorite, only: %i[update destroy], module: 'messages' end $ ./bin/rails routes Prefix Verb URI Pattern Controller#Action message_favorite PATCH /messages/:message_id/favorite(.:format) messages/favorites#update PUT /messages/:message_id/favorite(.:format) messages/favorites#update DELETE /messages/:message_id/favorite(.:format) messages/favorites#destroy ...
  • 28. 再考 - コントローラ # app/controllers/messages/favorites_controller.rb class < Messages::FavoritesController before_action :set_message def update respond_to do |format| if @message.update(favorited: true) format.html { redirect_to @message, notice: 'Favorited.' } else format.html { redirect_to @message, alert: 'Favorite failed.' } end end end def destroy respond_to do |format| if @message.update(favorited: false) format.html { redirect_to @message, notice: 'Unfavorited.' } else format.html { redirect_to @message, alert: 'Unfavorite failed.' } end end end private def set_message @message = Message.find(params[:message_id]) end end # (json 省略.)
  • 30. template inheritance #とは — ビューはどのディレクトリ/ファイルを探索する? — app/views/コントローラ名/アクション名.拡張子 みたいなところ? — ➡ だいたいあってるけどもうひといき — ➡ ❓
  • 31. template inheritance #とは — ビューはどのディレクトリ/ファイルを探索する? — app/views/コントローラ名/アクション名.拡張子 みたいなところ? — ➡ だいたいあってるけどもうひといき — ➡ コントローラの継承ツリーがヒントになっている
  • 32. view template の探索順序 — コントローラの継承ツリー — MessagesController — < ApplicationController — ➡ 以下の順に探索される 1. app/views/messages/* 2. app/views/application/*
  • 33. view template の探索順序 — 例えば Messages のサブクラスの Foos を作ったら — FoosController < MessagesController — ➡ 以下の順に探索される 1. app/views/foos/* 2. app/views/messages/* 3. app/views/application/*
  • 34. ちょっとためそう $ mkdir app/views/application $ mv app/views/messages/index.html.erb app/views/application/ ➡ 場所移しても動く. $ cp app/views/application/index.html.erb app/views/messages/index.html.erb $ echo '<h2>ほげ</h2>' >> app/views/messages/index.html.erb ➡ messages/ が優先.
  • 35. みんな ApplicationController を継承してるということは — app/views/application/ は共通ビューテンプレ ート置き場に使える. — しかも, 場合によっては各々のコントローラで上書き できる. — これ知らずに app/views/shared/* とか作るより Rails way かと.
  • 36. たとえばこんなルーティング — /messages - メッセージ一覧 — これに対して、 /messages/draft という URL を準 備する — 基本的には /messages と同じ. — ただし, published が false のデータでフィルタ された状態とする.
  • 37. /messages/draft をつくる - 1/4 app/controllers/messages_controller.rb def index - @messages = Message.all + @messages = message_scope end private + def message_scope + Message.all + end + def set_message
  • 38. /messages/draft をつくる - 2/4 app/controllers/messages/ drafts_controller.rb class Messages::DraftsController < MessagesController private def message_scope Message.where(published: false) end end
  • 39. /messages/draft をつくる - 3/4 config/routes.rb Rails.application.routes.draw do + namespace :messages do + resources :drafts, only: %i[index] + end resources :messages end
  • 40. /messages/draft をつくる - 4/4 config/routes.rb Rails.application.routes.draw do namespace :messages do - resources :drafts, only: %i[index] + resources :drafts, only: %i[index], path: 'draft' end resources :messages end ➡ 以上 ❗ ビューの修正などはなし
  • 41. まとめ — scaffold の吐くコントローラは良いコード. — routes にはなるべく resource(s) だけを記述. — URIでデザインするリソースと DB永続化は別の話. — template inheritance をうまく使おう. — 共通のテンプレートは app/views/application/ ディレクトリ