一連の記事の目次
rails、君に決めた!!~目次
前回の記事
rails、君に決めた!!~3
コントローラ
コントローラの命名規則
リソースの複数形Controller
リソースがpersonの時はPeopleController
複数形分からないよって時はpluralize
を使う
$ bin/rails c
Loading development environment (Rails 5.1.5)
[1] pry(main)> 'person'.pluralize
=> "people"
[2] pry(main)> 'chocolate'.pluralize
=> "chocolates"
単数形はsingularize
至れり尽くせりで笑う
ApplicationController
全てのコントローラの生みの親
共通処理はここに書く(セキュリティ設定、例外処理、コールバックなど)
app/controllers以下に色々なコントローラが生成されている
HTTPリクエストのパラメータを受け取る
HTTPリクエストで利用できるパラメータ送信方法は4種類
1. パスパラメータ
2. queryパラメータ
3. Body
4. カスタムヘッダ
このうち1,2,3はparams[]
で扱うことができる。
実際にparamsの中身を確認してみよう。
app/controllers/application_controller.rbを下のように変更し、
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# 追加
def hello
text = "PARAMS: #{params}"
render plain: text
end
end
http://localhost:3000/hello?p=foo&q=bar
にアクセスすると、画面にPARAMS: {"p"=>"foo", "q"=>"bar", "controller"=>"application", "action"=>"hello"}
と表示される。
注意点
text = "PARAMS: #{params}"
のダブルクオート""
をシングルクオート''
にすると、変数の埋め込みができなくなる。。。引っかかったで笑
Strong Parameters
強いパラメータとはなんぞや
Railsアプリに送信されたパラメータを安全に扱うための仕組み
強さとは安全を意味するらしい、真理だ笑
例として、新規ユーザー登録を行う機能について考える。
処理の流れ
フォーム画面 →userオブジェクトをPOST →サーバーがデータを適切な形に変換してデータベースに保存
脆弱性を含む例
def create
# params[:user] => {name: 'Ichiro', email: '~@.com'}
User.create(params[:user])
end
なぜこれはダメなのか。
例えば、悪意のあるユーザーがuserオブジェクトに、管理者を意味する{admin: true}のような属性を付加し、サーバーにPOSTしたとする。もしデータベースにadminというカラムが存在していたら、admin属性のユーザーが作成されてしまう。
なるほど、name,email属性だけ送ってくればいいのに悪い人がadmin属性も加えて送って来たりすると管理者権限とられちゃうってことか!
Strong Parametersを使った例
def create
User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :email)
end
params[:user]を直接呼ばずにuser_paramsメソッドを呼んでいる。
- requireメソッド
paramsの中にちゃんとuserオブジェクトが必須パラメータとして入っているか検証した後、userの中身を返す - permitメソッド
更新や追加していい属性をホワイトリスト方式で制限
これでadmin属性を除外できてよきよき。
コントローラをもうちょっと詳しく作ってみる
コントローラ=アクション+フィルタ
アクション: index,showなどのメソッド
フィルタ: アクションの前後に共通処理を実行する仕組み
user系を作り直すので、以下のコードを実行する
bin/rails d scaffold user
bin/rails db:migrate:reset
scaffoldで生成したuserを削除して、データベースもリセット
新たにusers コントローラを作る
bin/rails g controller users index show
生成されたusres_controller.rbの中身をみてみる。
class UsersController < ApplicationController
def index
end
def show
end
end
指定したindex,showアクションあるね、よしよし。
config/routes.rbを変更
ビフォー
Rails.application.routes.draw do
get 'users/index'
get 'users/show'
resources :articles
get 'home/index'
end
アフター
Rails.application.routes.draw do
resources :users, only: [:index, :show]
resources :articles
get 'home/index'
end
ビフォーだとURLがRESTじゃないんだと。
ビフォーのルーティング
Prefix Verb URI Pattern Controller#Action
users_index GET /users/index(.:format) users#index
users_show GET /users/show(.:format) users#show
アフターのルーティング
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
ルートを見比べてみると確かにって感じだ
フィルタを設定する
フィルタは以下の3種類
before_action
after_action
around_action
前、後ろ、両方ってだけ
実装のイメージ
class UsersController < ApplicationController
before_action :require_login, only: [:index]
def index
# 何か処理
end
private
def require_login
reject_to login_url unless singed_in?
end
end
indexアクションを実行する前にrequire_loginメソッドを実行する。未ログインならindexアクションを実行せず、ログインページに飛ばしてくれる。
引数を取るメソッドをフィルタにしたい場合は、
blockでもフィルタを定義できる
親クラスで定義したフィルタは、子クラスでskip_xxx_actionで例外的に無効化できる
疲れた〜ー
次回はセッション管理!
ついにredisを使うときがきた