【Rails】renderとredirect_toはどう使い分けるの?
はじめに
動作が似ているrenderとredirect_to
あまり意識せずに両者を使っていたので、それぞれの違いを調べてみました
renderとredirect_toの動き方の違い
redirect_toの方が多くの過程があり、具体的には以下のような過程の違いがあります。
・render: controller → view
・redirect_to: controller → URL → route → controller → view
renderとredirect_toの使い分け
renderはcontrollerで処理した結果を、指定したviewファイルに出力します。
redirect_toはviewファイルに出力する前に、1度ブラウザ上でURL(HTTPリクエスト)を指定し、再度controllerにリクエストを送信してから、viewファイルに出力します。
以上のことから、
データを追加、更新、削除を行うときは「redirect_to」、そうでなければ「render」という使いわけができそうです。
renderとredirect_toに関するエラー
1つのActionからは1つのViewしか返せません。 そのため、renderメソッドを2度呼び出したり、renderメソッドとredirect_toメソッドを両方呼び出すと、DoubleRenderErrorが発生します。
まとめ
「render」と「redirect_to」は動作が似ていますが、データの更新が必要な場合は「redirect_to」を、ログインや入力形式に失敗した場合など、ただエラーを表示させるだけの場合は「render」を使用する。というような使い分けができると思います。
参考
【Ruby】ローカル変数に代入がされていなくてもエラーにならない
はじめに
Rubyはif文やunless文の場合、実際にローカル変数に代入がされていなくても、代入を行う記述が存在すればローカル変数を宣言したこととなる
以下のコードでは変数「num」が宣言されていないので、エラーが発生する
if num % 2 == 0 message = "偶数" end puts message
=> undefined local variable or method `num' for main:Object (NameError)
変数「num」を宣言し、再度実行してみると「nil」が返ってきた
num = 1 if num % 2 == 0 message = "偶数" end p message
=> nil
変数「num」を宣言しても、if文の内容が実行されない(変数「message」の代入が行われない)ため、エラーが発生すると思っていたが、そうではなかった
Rubyはif文やunless文の場合、そのコードが実行されなくても(変数に代入がされなくても)ローカル変数を宣言したこととなる
まとめ
実際に代入がされていなくても、代入を行う記述が存在すればローカル変数を宣言したととなることがわかった。ただ、可読性を高めるためにも、if文やunless文の外で変数を代入し、変数が宣言されていることを明確にしたほうが良さそう
参考
【SQL】WHEREとHAVINGの違い
どちらも絞り込みを行うが、WHEREとHAVINGはなにが違うのか
→ 呼ばれるタイミングが違う
SQLが実行される順序
FROM → WHERE → GROUPBY → HAVING → SELECT → ORDERBY
呼ばれるタイミングが違うとどう変わる?
WHEREとGROUP BYを併用した場合
WHERE → GROUP BYの順でクエリが評価されるため、グループ化された結果に対しWHEREで条件を指定することができない
HAVINGとGROUP BYを利用した場合
GROUP BY → HAVINGの順でクエリが評価されるため、グループ化された結果に対しHAVINGで条件を指定することができる
SQLの実行結果の違いを確認してみる
以下の家計簿テーブルから、出金項目別に出金額合計を取り出す
出金項目 | 出金額 |
---|---|
食費 | 1000 |
光熱費 | 3000 |
交通費 | 3000 |
食費 | 2000 |
交通費 | 1000 |
食費 | 2000 |
交際費 | 0 |
WHEREを使ったSQL例)
SELECT 出金項目, SUM (出金額) AS 出金項目別の出金額合計 FROM 家計簿 WHERE SUM(出金額) > 0 GROUP BY 出金項目
実行結果
-> エラー
WHEREとGROUP BYを併用した場合、WHERE → GROUP BYの順でクエリが評価される。 そのため、グループ化された結果(GROUP BY 出金項目)に対し、WHEREは使えないのでエラーとなる
HAVINGを使ったSQL例)
SELECT 出金項目, SUM (出金額) AS 出金項目別の出金額合計 FROM 家計簿 GROUP BY 出金項目 HAVING SUM(出金額) > 0
実行結果
出金項目 | 出金額 |
---|---|
食費 | 5000 |
光熱費 | 3000 |
交通費 | 4000 |
HAVINGとGROUP BYを利用した場合、GROUP BY → HAVINGの順でクエリが評価される。 そのため、グループ化された結果(GROUP BY 出金項目)に対し条件を指定することが可能
まとめ
「WHERE」と「HAVING」違いは、呼ばれるタイミング(「WHERE」→「GROUP BY」→「HAVING」)にあった。 したがって「GROUP BY」が関わらなければ、同じ結果を得られる。 また、集計関数は対象のデータ数が少ないほど効率性が高まる。集計関数を行う際は、絞り込みの条件に「GROUP BY」が関わらないのであれば、HAVINGではなく、WHEREにより条件を絞り込んでから集計関数を実行することで、SQLの効率性を高めることができる。 WHEREとHAVINGの特性を理解した上で、効率の良いSQLを書くようにしたい。
参考
https://www.atmarkit.co.jp/ait/articles/0706/21/news128.html
メールアドレスの正規表現を考えてみた
メールアドレスの正規表現をネットで検索してみると、、、
短くシンプルなものから
[^\s]+@[^\s]+
このような長いものまであった。
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
自分でもメールアドレスのルールを以下のように仮定し、正規表現を考えてみた。
メールアドレスのルール
使える文字はアルファベット大文字小文字 (a~z, A~Z) 、数字 (0~9)、ピリオド「.」、アンダースコア「_」、ハイフン「-」、アットマーク「@」
@の前後に1文字以上の文字列が存在する
文字列の最初の文字は、アルファベットか数字であること
@は1個
@の後の最初の文字は、ピリオド(.)以外
@から2文字以降から末尾の間にピリオド(.)が1つ以上存在する
これらの条件を満たすよう考えた正規表現がこちら
/^[a-zA-Z\d]+[\w\.-]*@[\w-]+\.[\w\-]+[\w\.-]*$/
それぞれ分解して意味を確認していく
① / /で囲んだ間に正規表現のパターンを記載する
② ^ 先頭を表す
③ [a-zA-Z\d] アルファベットと数字のいずれかを表す
④ + 直前の文字が1個以上であることを表す
⑤ ^[a-zA-Z\d]+ 先頭には文字列(アルファベットと数字のいずれか)が1個以上存在することを表す
⑥ \w アルファベットと数字とアンダーバー「_」を表す
⑦ * 直前の文字が0個以上存在することを表す
⑧ [\w.-]* 文字列(アルファベットと数字とアンダーバー「.」とピリオド「.」とハイフン「-」のいずれか)が0個以上存在することを表す
⑨ @[\w-]+ アットマーク「@」の後ろに文字列(アルファベットと数字とアンダーバー「_」とハイフン「-」いずれか)が1個以上存在することを表す
⑩ .[\w-]+ ピリオド「.」の後ろに文字列(アルファベットか数字かアンダーバー「_」かハイフン「-」)が1個以上存在することを表す
⑪ $ 末尾を表す
⑫ [\w.-]*$ 末尾に文字列(アルファベットか数字かアンダーバー「_」かピリオド「.」かハイフン「-」)が0個以上存在することを表す
冒頭の2つの正規表現と比べてみる
①シンプルなもの
[^\s]+@[^\s]+
②少し長め
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
③今回自分が作ってみたもの
/^[a-zA-Z\d]+[\w\.-]*@[\w-]+\.[\w\-]+[\w\.-]*$/
3つの正規表現で共通している点は
- 文字列の間にアットマーク「@」が1個存在すること
- アットマーク「@」の前後に文字列が1個以上存在すること
反対に主な相違点は、先頭の文字列
①では
[^\s]
スペース以外の文字であれば良いというシンプルな表現
②では
\^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]
①の正規表現ほどではないが、英数字以外にもたくさんの記号が使える
③では
\^[a-zA-Z\d]+[\w\.-]*
先頭の文字には英数字しか使えない制限が存在する
また、②の[a-zA-Z0-9]と③[a-zA-Z\d]は少し形は違うが、意味としては全く同じ(アルファベットと数字を表す)となる
まとめ
メールアドレスの正規表現は上記以外にもたくさんネット上に転がっていた。理由としては、メールアドレスの形式が共通化されていないことや、正規表現には、同じ意味でも異なった表現方法が多々存在することなどが考えられる。表現したいことに合わせてルールを厳しくしたり、逆に簡易的なものにしたり、柔軟に対応できるようにしたい。
参考
https://qiita.com/matsubo/items/3dfb1ddb6e155c44643b https://qiita.com/sakuro/items/1eaa307609ceaaf51123 https://qiita.com/jnchito/items/893c887fbf19e17d3ff9
テーブル設計をする際に気をつけたいこと
テーブル設計を試みた際に、テーブルの構造をどうすれば良いのか不明確だったため、調べつつ4つのルールにまとめてみた。
テーブル設計のルール
ルール1
テーブルはある共通の属性を持ったモノの集合であること
表1はテーブルとはいえない。表2はテーブルといえる
表1 共通の属性を持たない
列1 | 列2 | 列3 | 列4 |
---|---|---|---|
食べ物 | 刺し身 | 焼き肉 | そば |
佐藤さん | 田中さん | 福田さん | 塩田さん |
ボーナス | ゲーム | 旅行 | 温泉 |
表2 共通の属性を持つ
原子番号 | 元素記号 | 元素名 |
---|---|---|
1 | H | 水素 |
2 | He | ヘリウム |
3 | Li | リチウム |
ルール2
レコードを1行に特定できる主キーが存在すること
表3は同性同名・同年齢・同じ性別の人の区別がつかない。表4は主キーにより特定することが可能
表3 主キーが存在しない
名前 | 年齢 | 性別 |
---|---|---|
鈴木一郎 | 25 | 男 |
鈴木一郎 | 25 | 男 |
田中修 | 30 | 男 |
表4 主キー(社員ID)が存在する
社員ID | 名前 | 年齢 | 性別 |
---|---|---|---|
001 | 鈴木一郎 | 25 | 男 |
002 | 鈴木一郎 | 25 | 男 |
003 | 田中修 | 30 | 男 |
ルール3
1つのセルに複数の値が存在してはいけない
表5は1つのセルに複数の値が存在している。表5を表6と表7に分割することで、セルの値を1つにできる
表5 1つのセルに複数の値が存在している
社員ID | 名前 | 年齢 | 性別 | 兄弟 |
---|---|---|---|---|
001 | 鈴木一郎 | 25 | 男 | 次郎 |
002 | 鈴木一郎 | 25 | 男 | 悦子 |
003 | 田中修 | 30 | 男 | 聡, 小春 |
表6 社員
社員ID | 名前 | 年齢 | 性別 |
---|---|---|---|
001 | 鈴木一郎 | 25 | 男 |
002 | 鈴木一郎 | 25 | 男 |
003 | 田中修 | 30 | 男 |
表7 社員・兄弟
社員ID | 兄弟番号 | 兄弟の名前 |
---|---|---|
001 | 1 | 次郎 |
002 | 1 | 悦子 |
003 | 1 | 聡 |
003 | 2 | 小春 |
ルール4 「推移関数従属」が存在しないこと
「推移関数従属」とは、主キーから見て2段階の関数従属が存在しているもの。
表8は「推移関数従属」が存在しており、新しく業界名を追加しようとしてもできない。表8を表9と表10に分割することで、「推移関数従属」を無くすことができる。
表8 2段階の関数(推移関数従属)が存在している
企業ID | 企業名 | 業界コード | 業界名 |
---|---|---|---|
001 | A商社 | 001 | 不動産 |
002 | B株式会社 | 002 | 電力 |
003 | C研究所 | 003 | 医療 |
表9 企業テーブル(推移関数従属が存在しない)
企業ID | 企業名 | 業界コード |
---|---|---|
001 | A商社 | 001 |
002 | B株式会社 | 002 |
003 | C研究所 | 003 |
004 | Dテクノロジー | 004 |
表10 業界テーブル(推移関数従属が存在しない)
業界コード | 業界名 |
---|---|
001 | 不動産 |
002 | 電力 |
003 | 医療 |
004 | IT |
まとめ
テーブル設計をする際に気をつけるポイントがわかった。特に推移的関数従属が存在するかどうか見極め、正しくテーブルを分解したい。
参考
おうちで学べるデータベースのきほん ミック (著), 木村 明治 (著)
【Rails】nil? empty? blank? present? 比較してみた
nil? empty? blank? present? 比較表
nil? | empty? | blank? | present? | |
---|---|---|---|---|
nil | true | NoMethodError | true | false |
true | false | NoMethodError | false | true |
false | false | NoMethodError | true | false |
0 | false | NoMethodError | false | true |
123 数字 |
false | NoMethodError | false | true |
'' 空 |
false | true | true | false |
' ' スペース |
false | false | true | false |
'string' 文字列 |
false | false | false | true |
[] 空配列 |
false | true | true | false |
['dog', 'cat'] 配列 |
false | false | false | true |
{} ハッシュ(空) |
false | true | true | false |
{:key => value} ハッシュ |
false | false | false | true |
nil?
値がnilの場合はtrue、それ以外はすべてfalseと判定する。
empty?
配列や文字列、ハッシュの値が空である場合にtrueと判定する。特徴的なのが、文字列のスペース(' ')に対してfalseと判定するところ。スペースも存在してるんだと認める女神的な?メソッド。ただし、値が空かどうか既に明白なもの(nil、true、false、数字)に対して行うとエラー発生させる厳しい側面もある。
blank?
英語「blank」の意味は「白紙、空、虚ろな」といったイメージ。そのイメージ通りfalse、空の配列、空の文字列(スペースも含む)をtrueと判定する。
present?
present?は、blank?と真逆。
まとめ
blank?とempty?ってややこしい。blank?の方が使い勝手がよさそう。empty?と違ってエラーが起きる心配も少ないし。でも意識して使い分けることができれば、コードの理解が深まる気がする。
参考
rubyの真偽判定メソッド(nil?/empty?/blank?/present?)を検証してみた結果、興味深いことがわかった - Qiita
【Ruby】mapメソッドと&とシンボルを使ってリファクタリングしてみた!
標準入力される整数 3, 100(この順で半角スペース区切り)の値を、int型にしてそれぞれの変数に代入する!
やることはこれだけですが、リファクタリングする前と後でコードが見違えた。
リファクタリングする前
input_value = gets.split(' ') value1 = input_value[0].to_i value2 = input_value[1].to_i
p input_value # => ["3", "100"] p value1 # => 3 p value2 # => 100
to_iを2回やってるのことにやや冗長さを感じる
mapメソッドでまとめてto_i
input_value = gets.split(' ').map{ |n| n.to_i } value1 = input_value[0] value2 = input_value[1]
p input_value # => [3, 100] p value1 # => 3 p value2 # => 100
ちなみに以下のようにmapメソッドを使わずにやるとエラーが出ます
input_value = gets.split(' ').to_i undefined method `to_i' for ["3", "100"]:Array (NoMethodError)
&とシンボルを使ってさらに簡潔に!
input_value = gets.split(' ').map(&:to_i) value1 = input_value[0] value2 = input_value[1]
p input_value # => [3, 100] p value1 # => 3 p value2 # => 100
ただし&とシンボルを使ったこの記法は、次の条件を満たしている必要があります
- ブロックの引数が1つ
- ブロックの中で呼び出すメソッドには引数がない
- ブロックの中では、ブロック引数に対してメソッドを1回呼び出す以外の処理がない
まとめ
繰り返し処理をやるときはeachを使いがちだけど、ループした結果を空の配列に入れるような処理はmapメソッドを使うことで簡潔に書ける。
参考
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで 伊藤 淳一 技術評論社 2017-11-25 p96〜P99