【メモ】herokuにRailsアプリケーションをデプロイするときのコマンド
うっかり忘れがちなので自分用にメモにまとめておく。
// ログイン $ heroku login // アプリケーション作成 $ heroku create my-rails-app // 作成されたか確認 $ heroku apps my-rails-app // herokuにpush $ git push heroku master // pushされたか確認 $ git remote -v heroku https://git.heroku.com/my-rails-app.git (fetch) heroku https://git.heroku.com/my-rails-app.git (push) origin https://github.com/mom0tomo/my-rails-app.git (fetch) origin https://github.com/mom0tomo/my-rails-app.git (push) // herokuでdb:migrate $ heroku run rails db:migrate
heroku run rails db:migrate
忘れがち。
Rails kaminariでページネーションを実装する
読んだもの
学んだこと
kaminariの使い方はすごく簡単。
tasks_controller.rb
def index @tasks = Task.all.page(params[:page]) # @tasks = Task.all <- kaminari利用前のコード end
index.html.erb
<h1>タスク一覧</h1> <ul> <% @tasks.each do |task| %> <li> <%= link_to task.id, task_path(task) %> : <%= task.content %> </li> <% end %> </ul> # ページネーションしたいところに記述する <%= paginate @tasks %> <%= link_to '新しいタスクを登録', new_task_path %>
controllerのTask.all部分に .page(params[:page])
を追加して、viewのページネーションしたいところに <%= paginate @tasks %>
をつけるだけ。
表示数を変更する
1ページの表示数はデフォルトで26に設定されており、変更したいときは .per(number)
をつける。
def index @tasks = Task.all.page(params[:page]).per(10) end
表示順番を降順にする
表示順番を降順にしたい場合は、Controller側で order
を指定する。
tasks_controller.rb
def index @tasks = Task.order(created_at: :desc).page(params[:page]).per(10) end
こんな感じ。
Railsでパーシャルを切り出すときはインスタンス変数をローカル変数にする
new.html.erb
<h1>新規タスク作成</h1> <%= form_for(@task) do |f| %> <% f.label :content, 'タスク' %> <% f.text_field :content %> <% f.submit '登録' %> <% end %> <%= link_to '一覧に戻る', tasks_path %>
edit.html.erb
<h1>タスク編集画面</h1> <p><%= @task.content %></p> <%= form_for(@task) do |f| %> <% f.label :content, 'タスク' %> <% f.text_field :content %> <% f.submit '登録' %> <% end %> <%= link_to '一覧に戻る', tasks_path %>
こういうのがあったときに、共通部分(フォーム周りのところ)をパーシャルにして切り出したい。
学んだこと
以下のようなパーシャルをつくる。
_form.html.erb
<%= form_for(task) do |f| %> <%= f.label :content, 'タスク' %> <%= f.text_field :content %> <%= f.submit '登録'%> <% end %>
new.html.erb
<h1>新規タスク作成</h1> <%= render 'form', task: @task %> <%= link_to '一覧に戻る', tasks_path %>
edit.html.erb
<h1>タスク編集画面</h1> <p><%= @task.content %></p> <%= render 'form', task: @task %> <%= link_to '一覧に戻る', tasks_path %>
ポイントは以下の通り。
RailsでviewのフォームからcontrollerにPOSTでデータを送信する
RailsのCRUDの基本のところで、newアクションからcreateアクションにデータを送るあたりがよくわからなくなったのでまとめる。
学んだ事
formタグのPOSTメソッドとパラメータの関係
まずはRailsではなく素のHTMLで考える。
<form action="/" method="POST"> <label>名前: <input type="text" name="target_name"></label> <input type="submit" value="送信"> </form>
viewにこのようなフォームがある場合、
- ユーザからのアクションは全て、HTTPリクエストのGETメソッドやPOSTメソッドとしてWebサーバに送信される。
- HTTPリクエストのPOSTメソッドで送ったデータは、params(パラメータ)に格納される。
- Webサーバはリクエストをもとに、paramsに入っているユーザからのデータを処理し、レスポンスを返す。
これが基本。
Railsのnewアクション
app/controller/task_controller
class TasksController < ApplicationController before_action :set_task, only: [:show, :edit, :update, :destroy] def index @tasks = Task.all end def show end def new @task = Task.new end end
newアクションでは、対応するviewをPOST メソッドを送信する新規作成用の入力フォーム置き場として使う。
app/views/messages/new.html.erb
<h1>タスク新規作成ページ</h1> <%= form_for(@task) do |f| %> <%= f.label :content, 'タスク' %> <%= f.text_field :content %> <%= f.submit '登録' %> <% end %> <%= link_to '一覧に戻る', messages_path %>
上のようなviewを書く事で、POSTメソッドを使ったフォームが生成される。
<body> <div class="container"> <h1>新規タスク作成</h1> <form class="new_task" id="new_task" action="/tasks" accept-charset="UTF-8" method="post"> // POSTメソッドを使う <input name="utf8" type="hidden" value="✓" /> <input type="hidden" name="authenticity_token" value="1XF/tmSKY6ak0LovbntLa/AqaxPSPAG6Ak5YyBdA4W3ebzM8KilBV+Vxw5adGwhqPE7pEJ9mn3ZbgJdGKQsJ1w==" /> <label for="task_content">タスク</label> <input type="text" name="task[content]" id="task_content" /> <input type="submit" name="commit" value="登録" data-disable-with="登録" /> </form> <a href="/tasks">一覧に戻る</a> </div> </body>
viewから実際に生成されるHTMLはこんな感じになる。
Railsのcreate アクション
app/controller/task_controller
class TasksController < ApplicationController .... def new @task = Task.new end def create @task = Task.new(task_params) respond_to do |wants| if @task.save flash[:success] = 'Taskが登録されました' redirect_to @message else flash.now[:danger] = 'Taskが登録されませんでした' render :new end end end private def set_task @task = Task.find(params[:id]) end # ストロングパラメータ def task_params params.require(:task).permit(:content) end end
create アクションは、newのviewからPOSTで送信されたフォームのデータを処理する。
new からcreateへ送られてきたフォームの内容は params[:task]
に入る。
params[:task]
をそのまま使用するのはセキュリティ上よくないので、ストロングパラメータを使ってフィルタする。
パラメータがネストしているときのストロングパラメータの書き方
前回の応用編。
読んだもの
学んだこと
ネストしたパラメータのサンプル
{ "name": "momo", "address": { "prefecture": "Toyo", "city": "Shinagawa" } }
上記のようなネストした構造のパラメータについて、ストロングパラメータの書き方は以下の通り。
user_controller.rb
params.permit(:name, address: [:prefecture, :city])
ストロングパラメータの簡単なサンプル
読んだもの
学んだこと
- Railsではストロングパラメータを必ず使う
- フォームの受け渡しなどで使わないとエラーになる(警告)
ストロングパラメータの基本的な書き方
params.require(:user).permit(:name, :email, :password)
やっていること
以下の二つ。 1. requireでPOSTで受け取る値のキーを設定している 2. permitで許可するカラムを設定している
上の例ではname, email, password属性の値だけDBに入れるのを許可している。
サンプルコード
実際に書くときはこんな感じ。
task_controller.rb
class TasksController < ApplicationController def index @tasks = Task.all end def show @task = Task.find(params[:id]) end def update @task = Task.find(params[:id]) if @task.update(task_params) redirect_to @task else flash.now[:danger] = 'Message は更新されませんでした' render :edit end end private # ストロングパラメータ def task_params params.require(:task).permit(:content) end end
Sinatra(Ruby)とGoの標準パッケージで立てたサーバを見比べる
たまたま同じ時期に0からサーバーを立てる機会に恵まれて、似てるなと思ったので比較してみる。
Sinatra
app.rb
require 'sinatra' get '/' do erb :index end
index.erb
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>タイトル</title> </head> <body> <p>Sinatraだよ</p> </body> </html>
Go
init.go
package main import "net/http" func init() { http.HandleFunc("/", index) }
index.go
package main import ( "html/template" "net/http" ) var indexTmpl = template.Must(template.New("index").Parse(`<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>タイトル</title> </head> <body> {{.}} </body> </html>`)) func index(w http.ResponseWriter, r *http.Request) { fmt.Println(w, "Goだよ") }
改めてGoの標準パッケージすごい。そして html/template
つらい。
selfを理解する
mom0tomo.hateblo.jp 前回の続き。
selfについて、実務であまり使うこともなくちゃんと理解しているのが怪しかったので確認する。
self は、クラス内部の変数やメソッドを明示して使うときに利用する。
class Person attr_accessor :name, :age def initialize self.name = 'もも' self.age = 22 end def cording(programing_language) puts "#{self.name}は#{programing_language}を利用しています。" end end mom0tomo = Person.new mom0tomo.cording('Go言語ʕ ◔ϖ◔ʔ') # ももはGo言語ʕ ◔ϖ◔ʔを利用しています。 p mom0tomo # #<Person:0x00007fa1b684d640 @name="もも", @age=22>
selfは、呼び出されたときのインスタンス (ここではmom0tomo)を指す。
つまり、mom0tomoインスタンスから cording('Go言語ʕ ◔ϖ◔ʔ')メソッドが呼び出されたとき、
mom0tomo.cording('Go言語ʕ ◔ϖ◔ʔ')
mom0tomo.
が、 self.
に代入される。
attr_accessorメソッド
attr_accessor はクラス内で変数を定義するためのメソッド。
下記のように、引数として与えられたシンボルをクラス内の変数として定義する。
class Person attr_accessor :name, :age def initialize self.name = 'もも' self.age = 22 end end mom0tomo = Person.new p mom0tomo
selfについては次回。
Rubyのattr_readerについて
読んだもの
学んだこと
attr_readerメソッドはアクセサメソッドを定義する。 アクセサメソッドとは、クラスやモジュールにインスタンス変数を読み出すためのメソッドである。 引数には、インスタンス変数名をシンボルか文字列で指定する。
下記はBookクラスにtitleメソッドとpriceメソッドを定義する例。beforeはattr_readerを使わない場合の書き方。
before
class Book def title @title end def price @price end end
上の例をattr_readerを書き直すと、下記のようになる。
after
class Book attr_reader :title, :price def initialize(title, price) @title = title; @price = price end end
Rubyのmapとeachの違い
読んだもの
すごくわかりやすかった。
学んだこと
each
eachはレシーバ自身が返る。
def each_sample (1..10).to_a.each do |i| i + 10 end end => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
レシーバ i が返っており、インクリメントはされていない。
map
mapはブロックの戻り値を集めて返す。
def map_sample (1..10).to_a.map do |i| i + 10 end end => [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Rubyのelsifとガード節について
コードレビューで、if elseは条件が対称な場合にだけ使った方が良いという指摘を受けた。
# if elseを使うのに適しているものの例 if number.odd? # 奇数の場合の処理 else # 偶数の場合の処理 end
上のように分岐の条件に対称性がある場合はif elseを使う。 そうでない場合は、早期リターンを使ったほうが意図が伝わりやすいという指摘だった。
読んだもの
blog.livedoor.jp techracho.bpsinc.jp
学んだこと
例
def display_kanri_fee # 管理費(画面表示用に整形する) if kanri_fee.blank? # 管理費がない場合 '- 円' => elsif kanri_fee_type.blank? # 月額/年額表示がない場合 number_to_currency(kanri_fee, unit: '円') else "#{number_to_currency(kanri_fee, unit: '円')} / #{kanri_type_i18n}" end end
ガード節で書き直す
def display_kanri_fee return '- 円' if kanri_feeblank? return number_to_currency(kanri_fee, unit: '円') if kanri_fee_type.blank? "#{number_to_currency(kanri_fee, unit: '円')} / #{kanri_type_i18n}" end
なるほど、わかりやすい気がする。
Railsのja.ymlでEnumの内容が被ったら
Enumの内容がかぶると、重複エラーになる。
You tried to define an enum named "monthly" on the model "Room", but this will generate a instance method "monthly?", which is already defined by another enum.
こういうときはprefixとsuffixをつけて区別してあげればいい。
読んだもの
学んだこと
修正前
model/Room.rb
enum yachin_type: { monthly: 1, # 月額 yearly: 2 # 年額 } enum kanrihi_type: { monthly: 1, # 月額 yearly: 2 # 年額 } # => 重複エラーになる
修正(prefixをつける場合)
model/Room.rb
enum yachin_type: { monthly: 1, # 月額 yearly: 2 # 年額 }, _prefix: :kanrihi_type enum kanrihi_type: { monthly: 1, # 月額 yearly: 2 # 年額 }
修正(suffixをつける場合)
model/Room.rb
enum yachin_type: { monthly: 1, # 月額 yearly: 2 # 年額 }, _suffix: true enum kanrihi_type: { monthly: 1, # 月額 yearly: 2 # 年額 }