毎日SEの技術ブログ

平日は社内SE、休みは自宅でサービス開発するSEの技術ブログ

Rails ActiveRecordのwhereで想定しないデータが取得される

はまったこと

# id='2a2'
model = model.where(relation_id: id)

を実行するとrelation_idが2のデータが取得される。

実行されたSQL

select model.* from model where model.relation_id = 2

原因はto_iメソッド

relation_idはinteger型なので、idがstring型だった時はwhereメソッド実行時にid.to_iが実行されidが数値に変換されます。

string.to_iメソッドは文字列を数値に変換しますが、'2a2'など、文字列と数値が混在しているときは先頭から数値に出来る部分までを切り出して数値化するようです。

'2a2'.to_i
# => 2

'25a'.to_i
# => 25

Rails flashの挙動

flashとは

  • 主にユーザに通知などを行う際に利用する
  • session機能を利用した機能
  • Hash形式

flashの使い方

controllerなどでflashに値を設定して、viewでflashから値を取得します。

#controller
flash[:error] = "エラーが発生しました"
#view
<%= flash[:error] %>

flashの値保持について

flashは通常次のリクエストまで保持され、その次のリクエスト時には破棄されます。

#controller
flash[:error] = "エラーが発生しました"
redirect_to 'hoge'
#hoge
<%= flash[:error] %>

この後更にリクエストを投げるときにはflash[:error]は存在しません。便利ですね。

しかし次のリクエストまで存在する為に、意識しておかないといけない点があります。

#controller
flash[:error] = "エラーが発生しました"
render action: 'hoge'
#hoge
<%= flash[:error] %>

このように処理すると次のリクエストが発生するのは画面表示された後になります。
直感的にはredirect_toと同じで一度表示したら破棄、のようなイメージになりますが、renderだとリクエストが発生しないため、redirect_toよりもワンテンポ寿命が長く感じられます。

例えばflashの内容を動的に取得してアラートを出すような処理をしていた場合、実際にアラートを出したい瞬間と、その次のリクエストとの二回アラートが出ることとなります。

renderなどリクエストが発生しないタイミングでflashを利用する際は設定時にflash.nowを使います。

#controller
flash.now[:error] = "エラーが発生しました"
render action: 'hoge'

flash.nowは現在のレスポンスだけで有効なため、次のリクエスト時には値が消えます。

逆にredirect_toするときにflash.nowを使用すると、リクエストが発生してしまうため値が取得できません。

JJUG ナイトセミナー 6.11 ドメイン駆動設計特集!に参加しました

GREEで行われたドメイン駆動設計(以下DDD)のイベントに参加してきました。

 

エリック・エヴァンスドメイン駆動設計を和訳した和智さんと、GREEに勤める加藤さんの二名がスピーカーです。

 

講演内容は下記二本立てです。

・コードに語らせるために(和智さん)

・DDDで実践するときに役に立つ話し(加藤さん)

 

本イベントは DDD入門者が対象であり、あまり深い話はされませんでした。

内容としては、以下に示すことがDDDを理解する上で最重要な考えであると感じています。

 

・DDDでの良い設計とは、非エンジニアでもわかる設計であること。

 

例えば、LINEのようなコミュニケーションツールがあったとします。

そのとき

・一つのメッセージをMessageクラス

・メッセージを発する人をUserクラス

と定義します。

 

"ユーザからメッセージがあるユーザに送信される"というシナリオを考えたとき、DDDの観点から見た、良くない設計と良い設計を示します。

 

・良くない設計

Message.send(from_user, to_user) 

"このメッセージをあるユーザからあるユーザに送信する"

とうような表現になり、非エンジニアに伝わりにくい設計となるからです。

 

・良い設計

User.send_message(message, to_user)

"ユーザからメッセージがあるユーザに送信される" という表現になりシナリオと一致し、非エンジニアに伝わりやすい設計となるからです。

 

良くない設計も良い設計も満たせる用件は同じです。

大切なのは、非エンジニアから見て分かりやすいか否かです。

非エンジニアが簡単だと思っている改修が簡単ではないのは、

非エンジニアの思い描いているモデルが、システムに反映できていないからです。