﹃ パ ー フ ェ ク ト R u b y o n R a i l s ﹄ ︵ す が わ ら ま さ の り , 前 島 真 一 , 近 藤 宇 智 朗 , 橋 立 友 宏 ︶ を 読 み ま し た 。 ﹁ R a i l s 開 発 に 慣 れ て き た か な ﹂ く ら い の 人 に ち ょ う ど い い 内 容 だ っ た と 思 い ま す 。 そ れ く ら い レ ベ ル の 人 が 少 し 上 を 目 指 し た り 、 よ り R a i l s ら し い 設 計 や 開 発 の 仕 方 を 学 ん だ り す る の に い い 書 籍 だ と 思 い ま し た 。 R u b y 2 や R a i l s 4 向 け の 説 明 に な っ て い る の で 、 新 し め の 情 報 を 得 た い よ う な 場 合 に も お 薦 め で す 。 逆 に 、 最 新 の R u b y や R a i l s で バ リ バ リ 開 発 し て い る よ う な 人 に は 既 知 の こ と ば か り で 物 足 り な い ん じ ゃ な い か な と い う 印 象 で す 。
全 体 的 に 興 味 は あ っ た の で す が 、 購 入 の 決 め 手 と な っ た の は 第 9 章 ﹁ よ り 実 践 的 な モ デ ル の 使 い 方 ﹂ で す 。 ど う 設 計 す る か 、 ど う リ フ ァ ク タ リ ン グ す る か の 1 つ の 指 針 と し て 読 ん で み た い と 思 い ま し た 。 実 際 に 読 ん だ 感 想 と し て は 、 学 び も 多 く 、 読 ん で よ か っ た と 思 い ま す 。
以 下 、 特 に 勉 強 に な っ た と こ ろ 、 気 に な っ た と こ ろ の メ モ で す 。 ち ょ く ち ょ く 載 せ て い る サ ン プ ル コ ー ド の う ち 明 示 し て い な い も の は 自 分 で 適 当 に 考 え た も の で す 。 本 書 に は よ り 適 切 な サ ン プ ル コ ー ド と 詳 し い 解 説 が 載 っ て い ま す の で ぜ ひ 購 入 し て ご 覧 に な っ て み て く だ さ い 。
第 1 章 R u b y o n R a i l s の 概 要
R a i l s を 扱 う た め の 準 備 や 概 要 に つ い て 書 か れ た 章 で す 。 R a i l s の 開 発 に 慣 れ て い る 人 は あ ま り 読 む 必 要 が な い と 思 い ま す 。
﹁ い つ も 開 発 環 境 の 準 備 と か 初 期 の 開 発 と か は 他 の 人 が や っ て く れ る の で 自 分 で は ほ と ん ど や っ た こ と な い ﹂ と か 、 ﹁ 普 段 の 環 境 と 自 宅 の 環 境 が 全 然 違 っ て い て 、 例 え ば 職 場 で は M a c に V M w a r e F u s i o n を イ ン ス ト ー ル し て 仮 想 環 境 で L i n u x O S を 動 か し て 開 発 し て い る け ど 自 宅 に は W i n d o w s マ シ ン し か な い ﹂ み た い な 、 準 備 に あ ま り 自 信 が な い よ う な 場 合 は 読 む 価 値 が あ る か も し れ ま せ ん 。
第 2 章 R u b y o n R a i l s と M V C
M V C に つ い て 書 か れ た 章 で す 。 R a i l s に お け る M V C の 考 え 方 、 具 体 的 な 開 発 イ メ ー ジ が 掴 め る と 思 い ま す 。 こ の 章 も 、 慣 れ て い る 人 は あ ま り 読 む 必 要 が な い と 思 い ま す 。
R a i l s で M V C の モ デ ル 、 ビ ュ ー 、 コ ン ト ロ ー ラ が そ れ ぞ れ ど う い う 扱 い な の か は ざ っ く り わ か り ま す が 、 き ち ん と M V C に つ い て 理 解 し た け れ ば 別 の 書 籍 や ネ ッ ト の 情 報 に あ た っ た ほ う が い い で す 。
実 際 の 開 発 で 使 う R a i l s 4 の い ろ い ろ な 機 能 に つ い て 解 説 さ れ て い る の で 、 そ の へ ん あ ま り 把 握 し て な い と い う 人 は 読 む と い い か も し れ ま せ ん 。 以 下 の よ う に 、 R a i l s 3 や 4 か ら 書 式 が 変 わ っ た り 新 機 能 と し て 実 装 さ れ た り し た も の も 解 説 さ れ て い ま す 。 リ リ ー ス ノ ー ト 読 む の 面 倒 臭 い か ら 手 っ 取 り 早 く 知 り た い と い う 方 に は ち ょ う ど い い か も し れ ま せ ん 。
● モ デ ル
● A r e l
● バ リ デ ー シ ョ ン
● A c t i v e R e c o r d e n u m s
● コ ン ト ロ ー ラ
● ル ー テ ィ ン グ 、 リ ソ ー ス
● S t r o n g P a r a m e t e r s
● ビ ュ ー
● v a r i a n t s
● H T M L エ ス ケ ー プ と r a w
メ ソ ッ ド
第 3 章 ア セ ッ ト
画 像 、 J a v a S c r i p t 、 S t y l e s h e e t な ど の ア セ ッ ト に つ い て 書 か れ た 章 で す 。 A s s e t P i p e l i n e の 仕 組 み と 活 用 法 に つ い て 書 か れ て い ま す 。
自 分 は A s s e t P i p e l i n e に つ い て の 理 解 が 浅 く 、 開 発 で も ほ と ん ど 触 れ た こ と が な い た め 、 興 味 深 く 読 み ま し た 。 C o f f e e S c r i p t や S a s s に つ い て も 簡 単 に 触 れ ら れ て い る の で 、 入 門 と し て は い い ん じ ゃ な い か と 思 い ま す 。
個 人 的 に は 、 テ ン プ レ ー ト の 拡 張 子 を 2 つ 以 上 重 ね る T i p が 新 し い 学 び で し た 。 例 え ば 、 t e s t . j s . c o f f e e . e r b と い う フ ァ イ ル 名 で 、 C o f f e e S c r i p t の フ ァ イ ル に E R B を 埋 め 込 め ま す 。
test.js.coffee.erb
1
2
3
4
<% 5 . times do | i | %>
notice <%= i %> = ->
alert ( "<%= i %>" )
<% end %>
それと、アセット関連の読み込み改善ということで、Turbolinks についても触れられています。概要や注意点について書かれているので、こちらも入門用としてはよさそうです。
第4章 Rails のロードパスとレイヤーの定義方法
モデル、ビュー、コントローラ以外のレイヤーを追加する方法と、その際に必要になるロードパスの考え方について書かれた章です。ワーカーやデコレーターといったレイヤーの追加の仕方を gem を紹介しながら説明しています。
個人的にはこういう設計に関するところは興味があったのでおもしろかったです。以下はメモ。
lib/autoload ディレクトリをオートロードさせるには、config/application.rb に以下のように記述します。
config/application.rb
1
2
3
4
5
class Application < Rails :: Application
config . autoload_paths += %w[#{config.root}/lib/autoload)
....
end
S i d e k i q と い う g e m を 使 う と 、 R a i l s か ら メ ッ セ ー ジ を 受 け 取 っ た ワ ー カ ー が R a i l s と は 別 に 立 ち 上 げ ら れ た プ ロ セ ス で 処 理 を 行 う こ と で 非 同 期 処 理 を 実 現 で き ま す 。 R e d i s が 必 要 で す 。
実 装 は 、 ワ ー カ ー ク ラ ス 内 で i n c l u d e S i d e k i q : : W
o r k e r
し て イ ン ス タ ン ス メ ソ ッ ド p e r f o r m
を 定 義 し ま す 。 p e r f o r m
の 引 数 は 、 J S O N で シ リ ア ラ イ ズ 可 能 な 値 の み 使 用 で き ま す 。
第 5 章 開 発 を 効 率 化 す る g e m
デ バ ッ グ の 効 率 化 や よ く 使 う コ マ ン ド の 高 速 化 を 行 う g e m を 紹 介 し た 章 で す 。
P r y : i r b を 高 機 能 に し た R E P L 環 境
●
ls
: 実 行 中 の ス コ ー プ 内 の 変 数 や メ ソ ッ ド の 一 覧 を 出 力
●
cd
: オ ブ ジ ェ ク ト の 中 へ 移 動 す る 。 対 象 の オ ブ ジ ェ ク ト の 状 態 を 詳 し く 調 べ ら れ る
●
s h o w - m e t h o d
: メ ソ ッ ド 定 義 を 参 照 す る 。 C 実 装 の 部 分 は ダ メ
●
s h o w - d o c
: ド キ ュ メ ン ト を 参 照 す る 。 C 実 装 の 部 分 は ダ メ
● ブ レ ー ク ポ イ ン ト の 設 定 、 ス テ ッ プ 実 行 ︵ b y e b u g g e m が 必 要 ︶
p r y - r a i l s を 使 う と 、 R a i l s c o n s o l e で も P r y を 使 え る よ う に な り ま す 。 ま た 、 以 下 の コ マ ン ド が 追 加 さ れ ま す 。
●
r e c o g n i z e - p a t h
: 引 数 に 渡 し た 文 字 列 な ど を ル ー テ ィ ン グ の a c t i o n や c o n t r o l l e r 情 報 に パ ー ス す る
●
s h o w - m i d d l e w a r e
: 読 み 込 ん で い る R a c k M i d d l e w a r e を 表 示 す る
●
s h o w - m o d e l
: 引 数 に 渡 し た モ デ ル の 情 報 を 出 力 す る
●
s h o w - m o d e l s
: す べ て の モ デ ル の 情 報 を 出 力 す る
●
s h o w - r o u t e s
: ル ー テ ィ ン グ 情 報 を 出 力 す る
H i r b : コ ン ソ ー ル 上 の モ デ ル の 出 力 を 整 形
A c t i v e R e c o r d : : B a s e イ ン ス タ ン ス の 出 力 が 表 形 式 に な り ま す 。 マ ル チ バ イ ト 文 字 を 扱 う 場 合 は h i r b - u n i c o d e g e m も 必 要 で す 。
P r y で H i r b を 利 用 す る 場 合 は . p r y r c に 設 定 を 記 述 し て お く と 便 利 で す 。
b i n d i n g _ o f _ c a l l e r g e m を 一 緒 に 使 う と 、 以 下 の よ う に さ ら に 便 利 に な り ま す 。
● 例 外 が 発 生 し た と き の 変 数 の 内 容 を 出 力
● 例 外 が 発 生 し た 時 点 の 状 態 で R E P L 環 境 が 起 動 、 オ ブ ジ ェ ク ト の 操 作 が 可 能 に
ラ イ ブ ラ リ ロ ー ド な ど が 短 縮 さ れ る の で 、 r a i l s
や r a k e
と い っ た コ マ ン ド が 高 速 化 し ま す 。 W i n d o w s 環 境 で は 動 き ま せ ん 。
r a k e
タ ス ク に e r d
が 追 加 さ れ ま す 。 実 行 す る と 、 G r a p h v i z を 使 っ て 描 画 さ れ た ER 図 が P D F で 出 力 さ れ ま す 。 つ ま り 、 G r a p h v i z 必 須 で す ︵ R と か 使 っ て い る 人 に は 定 番 ツ ー ル で す ね ︶ 。
第 6 章 R a i l s ア プ リ ケ ー シ ョ ン 開 発
実 際 の R a i l s ア プ リ ケ ー シ ョ ン 開 発 の チ ュ ー ト リ ア ル で す 。 R E S T f u l な ル ー テ ィ ン グ 、 B o o t s t r a p の 導 入 、 O A u t h 利 用 ︵ T w i t t e r で ロ グ イ ン ︶ 、 エ ラ ー ハ ン ド リ ン グ 、 K a m i n a r i g e m + k a m i n a r i - b o o t s t r a p g e m を 使 っ た ペ ー ジ ン グ ︵ ペ ー ジ ネ ー シ ョ ン ︶ 、 r a n s a c k g e m を 使 っ た 検 索 機 能 、 c a r r i e r w a v e g e m を 使 っ た 画 像 ア ッ プ ロ ー ド 機 能 に つ い て 書 か れ て い ま す 。
気 に な っ た 点 に つ い て 触 れ て い く と … …
ま ず 、 O A u t h の と こ ろ で 出 て き た 、 ﹁ l v m . m e ﹂ に つ い て は 初 め て 知 り ま し た 。
A b s t r a c t C o n t r o l l e r : : H e l p e r s : : C l a
s s M e t h o d s # h e l p e r _ m e t h o d
を 使 っ て コ ン ト ロ ー ラ か ら ヘ ル パ ー の メ ソ ッ ド を 呼 び 出 せ る よ う に で き る の は 忘 れ が ち で す 。
. / b i n / r a i l s g r e s o u r c e s
で リ ソ ー ス を 作 成 す る と 、 c o n f i g / r o u t e s . r b 内 に 自 動 で r e s o u
r c e s : e v e n t s
が 追 加 さ れ ま す 。
あ と 、 A c t i v e R e c o r d : : B a s e . f i n d _ b y !
の よ う に !
を つ け る と 見 つ か ら な か っ た と き に 例 外 を 発 生 さ せ ら れ る ん で す ね ︵ 古 い R a i l s で 提 供 さ れ て い た f i n d _ b y _ n a
m e
の よ う な D y n a m i c F i n d e r も 同 様 ︶ 。 恥 ず か し な が ら 知 り ま せ ん で し た … … 。 見 つ か ら な か っ た と き に 例 外 を 吐 く の は f i n d
く ら い か と 思 っ て い ま し た … … 。
r a n s a c k g e m は 使 っ て み た い g e m の 1 つ で す 。 w h
e r e
を 使 っ て い た と こ ろ を s e a r c h
に 置 き 換 え て 、 あ と は パ ラ メ ー タ 名 を 工 夫 す る と い い 感 じ の S Q L を 発 行 し て く れ ま す 。 ク ラ ス メ ソ ッ ド の r a n s a c k a b l e _ a t t r i b u t e s
や r a n s a c k a b l e _ a s s o c i a t i o n s
を 使 え ば 検 索 条 件 や 関 連 を 限 定 す る こ と も で き ま す 。
1
2
Event . search ( name_cont : "JavaScript" ) # equal to Event.where("name like ?", "%JavaScript%")
Event . search ( start_time_gteq : Time . now ) # equal to Event.where("start_time >= ?", Time.now)
画 像 ア ッ プ ロ ー ド 機 能 の と こ ろ で は 、 以 下 の よ う な 、 画 像 を 扱 う と き の 注 意 点 に つ い て も 触 れ ら れ て い て 参 考 に な り ま す 。 c a r r i e r w a v e - m a g i c g e m な ど を 使 う と m i m e - t y p e を 判 定 し た り も で き る の で す ね 。
● ア ッ プ ロ ー ド し た フ ァ イ ル を ど こ に 配 置 す る か
● サ イ ズ が 大 き い 画 像 を ア ッ プ ロ ー ド し た 場 合 に ど う す る か
● 画 像 以 外 の フ ァ イ ル を ア ッ プ ロ ー ド し た 場 合 は ど う す る か
最 後 に 、 R a i l s を 使 っ て 開 発 を す る 際 に 意 識 し て お く べ き 大 切 な こ と が 書 か れ て い ま す 。
… … ︵ R a i l s が 提 供 す る ︶ 機 能 を 学 ぶ 際 は 、 単 純 に 丸 暗 記 す る の で は な く ﹁ な ぜ こ の よ う な 機 能 が あ る の か ﹂ を 積 極 的 に 調 べ る よ う に し ま し ょ う 。 R a i l s が 提 供 し て い る 機 能 の 多 く は 、 W e b ア プ リ ケ ー シ ョ ン 開 発 全 般 で 使 え る ベ ス ト プ ラ ク テ ィ ス で す 。
… … た い て い の 場 合 、 実 装 方 法 の 選 択 肢 は 複 数 存 在 し ま す 。 選 択 肢 の 種 類 を 増 や す こ と と 、 そ の 中 か ら 適 切 な 実 装 方 法 を 選 ぶ こ と 、 両 方 と も 経 験 が 必 要 な こ と で す が 、 大 事 な の は 常 に 複 数 の 選 択 肢 が あ る こ と を 前 提 に 、 設 計 に 真 摯 に 向 き 合 う こ と で す 。
第 7 章 R a i l s ア プ リ ケ ー シ ョ ン の テ ス ト
R a i l s に お け る テ ス ト の 書 き 方 、 テ ス ト で 使 え る ツ ー ル 、 T D D ︵ テ ス ト 駆 動 開 発 ︶ に つ い て 書 か れ た 章 で す 。 m i n i t e s t と R S p e c の 比 較 な ん か も あ り 、 ど う い う 場 合 に ど ち ら が 適 切 か を 考 え る 1 つ の 指 針 に な る か も し れ ま せ ん 。 c a p y b a r a g e m 、 p o l t e r g e i s t を 使 っ た エ ン ド ツ ー エ ン ド の テ ス ト に つ い て も 書 か れ て い ま す 。 CI 、 カ バ レ ッ ジ 、 静 的 解 析 ︵ e . g . , B r a k e m a n g e m 、 r a i l s _ b e s t _ p r a c t i c e s g e m 、 C o d e C l i m a t e と い う サ ー ビ ス ︶ に も 少 し 触 れ ら れ て い ま す 。
本 章 で は 、 テ ス ト を 書 く 理 由 に つ い て 以 下 の よ う に 述 べ ら れ て い ま す 。
● テ ス ト 対 象 と な る 仕 様 と ア プ リ ケ ー シ ョ ン の 設 計 を 考 え る 機 会 が 増 え る
● ︵ 仕 様 の 抜 け 漏 れ を 減 ら す こ と が で き る ︶
● ︵ き れ い な 設 計 に で き る ︶
● 手 作 業 に よ る テ ス ト を 減 ら す こ と が で き る
● ﹁ こ こ は ち ゃ ん と 想 定 ど お り に 動 く だ ろ う か … … ﹂ と い う 不 安 を 減 ら せ る
● リ フ ァ ク タ リ ン グ や 仕 様 の 変 更 に 自 信 を 持 っ て 対 応 で き る
個 人 的 に 加 え る と す れ ば 、 ﹁ 仕 様 書 代 わ り に で き る ﹂ と い う 点 で し ょ う か 。 普 段 テ ス ト を 読 む と い う の は そ こ ま で や り ま せ ん が 、 あ る ク ラ ス や メ ソ ッ ド に つ い て 理 解 を 深 め た い と き に テ ス ト を 読 ん で 仕 様 を 把 握 し よ う と す る こ と が あ り ま す 。 特 に R S p e c を 使 う と よ り S p e c を 記 述 し や す い の で こ の ポ イ ン ト を 意 識 し て い ま す 。
本 の 内 容 に 戻 り ま す が 、 R S p e c を 使 う な ら s h o u l d a - m a t c h e r s g e m を 使 う と 幸 せ に な れ そ う で す ね 。
ダ ブ ル ︵ 他 の オ ブ ジ ェ ク ト の 代 わ り を す る オ ブ ジ ェ ク ト ︶ 、 ス タ ブ ︵ メ ソ ッ ド を 仮 に 定 義 し 、 メ ソ ッ ド が 実 行 さ れ た と き に 任 意 の 値 を 返 さ せ る ︶ に つ い て も 触 れ ら れ て い ま す 。 ダ ブ ル 、 ス タ ブ 、 モ ッ ク の 違 い に つ い て は い ろ い ろ 情 報 が あ る の で そ ち ら に 譲 り ま す ︵ ち な み に こ の へ ん の 違 い は 本 書 を 読 ん で も 詳 し く は わ か り ま せ ん ︶ 。
a s s i g n
メ ソ ッ ド で イ ン ス タ ン ス 変 数 に 値 を 設 定 で き ま す 。 た だ 、 @ h o g e = f u g a
と 書 い た り i n s t a n c e _ v a r i
a b l e _ s e t
し た り す る の と の 違 い が わ か っ て い ま せ ん 。 そ の う ち 調 べ ま す 。
c a p y b a r a は こ れ ま で 使 っ た こ と が あ り ま せ ん で し た 。 エ ン ド ツ ー エ ン ド の テ ス ト に 関 し て 個 人 的 に 気 に な っ た ポ イ ン ト は 以 下 で す 。
● c a p y b a r a は 、 ド ラ イ バ と 呼 ば れ る 仕 組 み に よ っ て 、 ﹁ ど の ブ ラ ウ ザ を 利 用 し て テ ス ト を す る の か ﹂ を 切 り 替 え ら れ る
● c a p y b a r a は s e l e n i u m ︵ ブ ラ ウ ザ を 操 作 し て テ ス ト す る ド ラ イ バ ︶ を サ ポ ー ト し て い る が 、 実 際 に は あ ま り 行 わ れ て い な い
● 実 行 時 間 が か か り す ぎ る た め
● ブ ラ ウ ザ を 動 か す た め の G U I 環 境 が 必 要 な た め 。 代 わ り に 、 c a p y b a r a - w e b k i t や p o l t e r g e i s t と い う ド ラ イ バ を 利 用 す る の が 一 般 的
● 最 近 は コ ン ト ロ ー ラ や ビ ュ ー の テ ス ト の 記 述 は 少 な く な る 傾 向 に あ る 。 た だ し 、 エ ン ド ツ ー エ ン ド の テ ス ト は 実 行 時 間 が か か る の で 、 内 容 か ら ど こ に 書 く べ き か を 判 断 し て 書 き わ け る こ と が 大 切
●
D a t a b a s e C l e a n e r g e m で 、 D a t a b a s e
C l e a n d e r . s t r a t e g y
を 切 り 替 え る こ と で 、 通 常 の テ ス ト で は ト ラ ン ザ ク シ ョ ン を 利 用 し 、 p o l t e r g e i s t を 利 用 し た テ ス ト で は t r u n c a t i o n で デ ー タ 削 除 す る と い う 使 い わ け が で き る
●
d e s c r i b e
の 第 2 引 数 に j s : t r u e
を 渡 す こ と で 、 c a p y b a r a に 対 し て J a v a S c r i p t 用 の ド ラ イ バ を 使 う こ と を 知 ら せ る
第 8 章 R a i l s の イ ン フ ラ と 運 用
サ ー バ の 構 築 や 構 成 管 理 、 ア プ リ ケ ー シ ョ ン の 配 備 ︵ デ プ ロ イ メ ン ト ︶ 、 監 視 に つ い て 書 か れ た 章 で す 。 V a g r a n t + C h e f を 使 っ た 環 境 の 構 築 方 法 、 C a p i s t r a n o の 使 い 方 、 N e w R e l i c の 使 い 方 が 書 か れ て い ま す 。
他 に も 、 以 下 の よ う な ツ ー ル / サ ー ビ ス が 紹 介 さ れ て い ま す 。
●
A i r b r a k e : エ ラ ー 通 知 と 解 析 に 特 化 し た S a a S
●
E x c e p t i o n n o t i f i c a t i o n : エ ラ ー 通 知 の た め の ラ イ ブ ラ リ
●
F l u e n t d : ロ グ の 収 集 に 特 化 し た サ ー バ ︵ ミ ド ル ウ ェ ア ︶ 。 R a i l s な ら 、 r a c k - c o m m o n _ l o g g e r - f l u e n t g e m を 使 う と 便 利
●
K i b a n a : F l u e n t d で 収 集 し た デ ー タ を 可 視 化 す る ア プ リ ケ ー シ ョ ン
第 9 章 よ り 実 践 的 な モ デ ル の 使 い 方
“ S k i n n y C o n t r o l l e r s , F a t M o d e l s ” ︵ コ ン ト ロ ー ラ を 薄 く 、 モ デ ル を 厚 く ︶ に 基 づ い て R a l s 開 発 を 進 め て い く と 、 ど ん ど ん モ デ ル が 肥 大 化 し ま す 。 こ の 問 題 に 対 し て 、 バ リ デ ー シ ョ ン お よ び コ ー ル バ ッ ク を 小 さ な ク ラ ス に 分 離 す る 方 法 、 A c t i v e M o d e l を 使 っ て R D B ︵ リ レ ー シ ョ ナ ル デ ー タ ベ ー ス ︶ に 依 存 し な い モ デ ル ク ラ ス を 定 義 す る 方 法 、 一 部 の 機 能 を A c t i v e R e c o r d モ デ ル の 外 に 抽 出 す る 方 法 が 紹 介 さ れ て い ま す 。
個 人 的 に は 、 本 書 の 中 で 最 も 読 み た か っ た と こ ろ で す 。 あ る 程 度 は ネ ッ ト 上 に 情 報 が あ る の で す が 、 R a i l s で 具 体 的 に ど う や る か が ま と ま っ て い る の が あ り が た か っ た で す 。
コ ー ル バ ッ ク 、 バ リ デ ー シ ョ ン を 小 さ な ク ラ ス に 分 離 す る
コ ー ル バ ッ ク の 分 離
コ ー ル バ ッ ク を ク ラ ス に 分 離 す る メ リ ッ ト は 本 書 に よ れ ば 以 下 の と お り で す 。
● コ ー ル バ ッ ク が 複 数 の フ ッ ク ポ イ ン ト に ま た が っ て 1 つ の 機 能 を 実 現 し て い る 場 合 、 そ れ ぞ れ の コ ー ル バ ッ ク の 関 係 性 を 明 確 に 表 現 で き る
● モ デ ル ク ラ ス は 本 来 の ビ ジ ネ ス ロ ジ ッ ク の 実 装 に 集 中 で き る
● 機 能 の 境 界 が は っ き り す る こ と で 、 テ ス ト を 行 い や す く な る
コ ー ル バ ッ ク に 渡 す こ と の で き る オ ブ ジ ェ ク ト は 、 そ の コ ー ル バ ッ ク の 名 前 と 同 じ 名 前 の イ ン ス タ ン ス メ ソ ッ ド を 実 装 し て い る 必 要 が あ り ま す 。 本 書 に も 引 用 さ れ て い る A c t i v e R e c o r d : : C a l l b a c k s の コ ー ド 例 は 以 下 で す 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class BankAccount < ActiveRecord :: Base
before_save EncryptionWrapper . new ( "credit_card_number" )
after_save EncryptionWrapper . new ( "credit_card_number" )
after_initialize EncryptionWrapper . new ( "credit_card_number" )
end
class EncryptionWrapper
def initialize ( attribute )
@attribute = attribute
end
def before_save ( record )
record . send ( " #{ @attribute } =" , encrypt ( record . send ( " #{ @attribute } " )))
end
def after_save ( record )
record . send ( " #{ @attribute } =" , decrypt ( record . send ( " #{ @attribute } " )))
end
alias_method :after_initialize , :after_save
private
def encrypt ( value )
# Secrecy is committed
end
def decrypt ( value )
# Secrecy is unveiled
end
end
バリデーションの分離
バ リ デ ー シ ョ ン を 分 離 す る メ リ ッ ト は 、 本 書 で は 以 下 の よ う に 述 べ ら れ て い ま す 。
● 責 任 の 境 界 が は っ き り す る
● テ ス ト が 容 易 に な る
A c t i v e M o d e l : : E a c h V a l i d a t o r
を 継 承 し た ク ラ ス を 定 義 す る と 、 モ デ ル で 使 う v a l i d a t e s
メ ソ ッ ド が そ の ク ラ ス 名 に 基 づ い た オ プ シ ョ ン を 受 け 取 れ る よ う に な り ま す 。 そ の 際 の 決 ま り 事 は 以 下 で す 。
● バ リ デ ー タ ク ラ ス に イ ン ス タ ン ス メ ソ ッ ド v a l i d a t e _ e a
c h
を 定 義 す る
●
v a l i d a t e _ e a c h
の 引 数 は モ デ ル の イ ン ス タ ン ス 、 属 性 名 、 属 性 値 の 3 つ
●
H o g e V a l i d a t o r
と い う ク ラ ス 名 の V a l i d a t o
r
を 除 い た 部 分 を u n d e r s c o r e
し た も の が オ プ シ ョ ン 名 と な る 。 H o g e V a l i d a t o r
な ら h o g e
既 存 の バ リ デ ー タ ク ラ ス を 継 承 し た サ ブ ク ラ ス を 定 義 し た り 、 新 し く 自 分 で バ リ デ ー タ ク ラ ス を 定 義 し た り す る こ と で 、 う ま く 検 証 ル ー ル を 整 理 で き ま す 。
以 下 で は 、 コ メ ン ト の 内 容 に 必 ず 褒 め 言 葉 を 入 れ る よ う に 強 制 し て い ま す ︵ … … ツ ッ コ ミ ど こ ろ 満 載 な 例 で す が ︶ 。
lib/autoload/must_praise_validator.rb
1
2
3
4
5
6
7
class MustPraiseValidator < ActiveModel :: EachValidator
def validate_each ( record , attribute , value )
unless value =~ /すばらしい|さすが|感動|ありがとう/
record . errors . add attribute , ( options [ :message ] || "は必ず褒めてください。" )
end
end
end
app/models/comment.rb
1
2
3
class Comment < ActiveRecord :: Base
validates :content , presence : true , must_praise : true
end
A c t i v e M o d e l : : V a l i d a t o r
ク ラ ス を 継 承 す る と 、 1 つ の 属 性 値 だ け に 留 ま ら な い 複 雑 な 検 証 ル ー ル を 扱 う ク ラ ス を 定 義 で き ま す 。 こ の ク ラ ス は 以 下 の よ う な 構 成 と な り ま す 。
● イ ン ス タ ン ス メ ソ ッ ド v a l i d a t e
が 定 義 さ れ て い る
●
v a l i d a t e
メ ソ ッ ド の 引 数 は モ デ ル の イ ン ス タ ン ス の み
● 実 際 に 使 う モ デ ル の ク ラ ス で ク ラ ス メ ソ ッ ド v a l i d a t e s _
w i t h
に 引 数 と し て バ リ デ ー タ ク ラ ス を 渡 す
以 下 は 、 E v e n t ク ラ ス の 開 始 時 刻 と 終 了 時 刻 が 入 力 さ れ た 場 合 に 正 し く 時 間 ︵ 範 囲 ︶ と し て 扱 え る か を 検 証 し て い ま す 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# name :string(255)
# start_time :datetime
# finish_time :datetime
# created_at :datetime
# updated_at :datetime
#
class Event < ActiveRecord :: Base
validates_with RangeableValidator , if : [ :start_time , :finish_time ]
end
class RangeableValidator < ActiveModel :: Validator
def validate ( record )
unless start_time < finish_time
record . errors . add :base , "終了時刻は開始時刻よりもあとにしてください。"
end
end
end
クラスを分離するメリット、デメリット
コ ー ル バ ッ ク や バ リ デ ー シ ョ ン を ク ラ ス に 分 離 す る デ メ リ ッ ト は 以 下 で す 。
● コ ー ド 量 が 増 加 す る
● 実 装 が 分 散 す る こ と で 、 モ デ ル ク ラ ス の 動 作 を 把 握 す る 手 間 が 増 え る
一 方 で 、 分 離 す る メ リ ッ ト と い う か 使 い ど こ ろ は 以 下 で す 。
● モ デ ル ク ラ ス の 制 約 か ら 分 離 す る : テ ス ト が 容 易 に な る 。 過 剰 な ト リ ッ ク を 使 わ ず に 機 能 の 本 質 を テ ス ト で き る
● 業 務 知 識 を 表 現 す る : 業 務 上 の ル ー ル と し て 重 要 な 場 合 、 そ の ル ー ル に 相 当 す る 名 前 で 分 離 す る こ と に よ り 、 業 務 上 の 概 念 と 設 計 上 の 概 念 を 一 致 さ せ ら れ る
注 意 点 と し て 、 対 象 と な る 制 約 条 件 が ど の 範 囲 で 利 用 さ れ る の か を 踏 ま え た 上 で 記 述 方 法 を 考 え る こ と が 大 切 と い う 点 に も 触 れ ら れ て い ま す 。 あ る 条 件 の と き に 一 部 の バ リ デ ー シ ョ ン や コ ー ル バ ッ ク だ け を 無 効 に す る と い う の は 手 間 が か か り 複 雑 に な り ま す 。 特 定 の 機 能 に つ い て の み 影 響 す る よ う な 制 約 条 件 に つ い て は 、 バ リ デ ー シ ョ ン や コ ー ル バ ッ ク と し て 表 現 す る の で は な く サ ー ビ ス ク ラ ス ︵ 後 述 ︶ の 中 に ま と め て し ま っ た ほ う が い い 場 合 も あ り ま す 。
ま た 、 分 離 す る 以 外 に も 、 特 定 の 機 能 に つ い て の 関 心 事 を モ ジ ュ ー ル に ま と め て 切 り 出 し て 表 現 す る こ と も で き ま す 。 こ の 方 法 は 後 述 の C o n c e r n で 詳 し く 記 述 さ れ て い ま す 。
A c t i v e M o d e l : デ ー タ ベ ー ス に 依 存 し な い モ デ ル を つ く る
デ ー タ ベ ー ス に は 対 応 し な い け れ ど 以 下 の よ う な A c t i v e R e c o r d の 便 利 な 機 能 を 持 っ た ク ラ ス を 定 義 し た い 場 合 、 A c t i v e M o d e l モ ジ ュ ー ル を 使 う と 便 利 で す 。
● バ リ デ ー シ ョ ン
● コ ー ル バ ッ ク
● 属 性 名 を 基 に し た 動 的 な メ ソ ッ ド を 定 義
● 属 性 値 に 対 す る 変 更 を 保 持 す る
● オ ブ ジ ェ ク ト の シ リ ア ラ イ ズ
本 書 で は 、 A c t i v e M o d e l の 機 能 の 中 で 代 表 的 な も の に つ い て 紹 介 し て い ま す 。
A c t i v e M o d e l : : A t t r i b u t e M e t h o d s
A c t i v e M o d e l : : A t t r i b u t e M e t h o d s は a t t r _ a c c e s s o r
な ど で 定 義 し た ア ク セ サ メ ソ ッ ド に 対 し メ ソ ッ ド を 宣 言 的 に 定 義 で き る 機 能 を 提 供 し ま す 。
A c t i v e M o d e l : : A t t r i b u t e M e t h o d s を i n c l u d e す る と 、 以 下 の ク ラ ス メ ソ ッ ド が 定 義 さ れ ま す 。
● a t t r i b u t e _ m e t h o d _ s u f f i x
● a t t r i b u t e _ m e t h o d _ p r e f i x
● a t t r i b u t e _ m e t h o d _ a f f i x
● d e f i n e _ a t t r i b u t e _ m e t h o d s
● a l i a s _ a t t r i b u t e
例 え ば 以 下 の よ う に 定 義 し た と す る と 、 以 下 の メ ソ ッ ド が 使 え る よ う に な り ま す 。
Person#upcase_first_name
Person#upcase_family_name
Person#upcase_first_name!
Person#upcase_family_name!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Person
include ActiveModel :: AttributeMethods
attribute_method_prefix "upcase_"
attribute_method_affix prefix : "upcase_" , suffix : "!"
define_attribute_methods :first_name , :family_name
attr_accessor :first_name , :family_name
def attributes
{
"first_name" => @first_name ,
"family_name" => @family_name ,
}
end
private
def upcase_attribute ( attr )
send ( attr ) . upcase
end
def upcase_attribute! ( attr )
send ( " #{ attr } =" , upcase_attribute ( attr ))
end
end
person = Person . new
person . first_name = "Jonathan"
person . family_name = "Joestar"
person . upcase_first_name #=> "JONATHAN"
person . upcase_family_name #=> "JOESTAR"
ActiveModel::Callbacks
A c t i v e M o d e l : : C a l l b a c k s は b e f o r e _
s a v e
や a f t e r _ c r e a t e
の よ う な コ ー ル バ ッ ク を 定 義 し や す く し て く れ る モ ジ ュ ー ル で す 。 A c t i v e R e c o r d と 同 様 の 記 述 ス タ イ ル で い い の で あ れ ば A c t i v e S u p p o r t : : C a l l b a c k s モ ジ ュ ー ル を 使 う よ り も 記 述 が 少 な く 簡 単 に 記 述 で き る と い う メ リ ッ ト が あ り ま す 。
使 い 方 は 以 下 の サ ン プ ル コ ー ド を 見 れ ば だ い た い わ か る と 思 い ま す 。 毎 回 r u n _ c a l l b a c k s
を 呼 び 出 し て あ げ な い と い け な い の が ち ょ っ と 面 倒 臭 い で す ね 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Hero
extend ActiveModel :: Callbacks
define_model_callbacks :appear # `before_appear` と `after_appear` を定義
define_model_callbacks :defeat , only : [ :before ] # `before_defeat` のみ定義
attr_accessor :skill_name
before_appear :transform
before_defeat :shout_skill_name
after_appear :lose
def transform
puts "変身!!"
end
def appear
run_callbacks :appear do
puts "参上!!"
end
end
def lose
puts "何……だと……"
end
def shout_skill_name
puts <<- EOS
_人人人人人人人人人_
> #{skill_name} <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
EOS
end
def defeat ( enemy )
run_callbacks :defeat do
puts "とどめだ、 #{ enemy . name } !!"
end
end
end
ActiveModel::Dirty
ActiveModel::Dirty を使うと、属性値の変化を追跡できるようになります。hoge_changed?
などのメソッドが使えるようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class User
include ActiveModel :: Dirty
define_attribute_methods :password
def password
@password
end
def password = ( value )
password_will_change! unless value == @password
@password = value
end
def save
@previously_changed = changes
@changed_attributes . clear
end
end
user = User . new
user . password_changed? #=> false
user . changed #=> []
user . changes #=> {}
user . password = "hoge"
user . password_changed? #=> true
user . changed #=> ["password"]
user . changes #=> { "password" => ["", "hoge"] }
user . save
user . password_changed? #=> false
user . changed #=> []
user . changes #=> {}
d e f i n e _ a t t r i b u t e _ m e t h o d s
を 使 用 し て い る こ と か ら わ か る よ う に 、 A c t i v e M o d e l : : D i r t y は 内 部 で A c t i v e M o d e l : : A t t r i b u t e M e t h o d s を 利 用 し て い ま す 。
変 更 の 追 跡 に は h o g e _ w i l l _ c h a n g e !
メ ソ ッ ド が 使 わ れ ま す 。 変 更 さ れ た と い う 状 態 を ク リ ア す る 際 は @ c h a n g e d
_ a t t r i b u t e s
を ク リ ア し ま す 。 前 回 の 変 更 内 容 を 保 持 す る に は @ p r e v i o u s l y _ c h a n g e d
に c h a n g e s
の 内 容 を 保 持 し て お き ま す 。
A c t i v e M o d e l : : N a m i n g
A c t i v e M o d e l : : N a m i n g を 使 う と 、 ク ラ ス が m o
d e l _ n a m e
メ ソ ッ ド を 使 え る よ う に な り ま す 。 m o d e l _ n
a m e
メ ソ ッ ド は 、 文 字 列 に 似 た A c t i v e M o d e l : : N a m e オ ブ ジ ェ ク ト の イ ン ス タ ン ス を 返 し 、 そ れ に よ り R a i l s の 命 名 規 約 や I 1 8 n を 利 用 し た 文 字 列 の 変 換 を 簡 単 に 処 理 で き る よ う に な り ま す 。
1
2
3
class User
extend ActiveModel :: Naming
end
似たモジュールとして、以下のようなものもあります。
モジュール名
内容
ActiveModel::Translation
I18n を利用するためのヘルパーメソッドを定義してくれる
ActiveModel::Conversion
オブジェクトを URL のパラメータとして利用したりファイルパスの検索キーとして利用しやすい形に変換してくれる
ActiveModel::Serialization
ActiveModel::Serialization は、json や xml 形式でオブジェクトをシリアライズする機能を追加します。実際にシリアライズする機能は ActiveModel::Serializers::JSON と ActiveModel::Serializers::XML に定義されているので、利用する際はこちらを include して使うことになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Comment
include ActiveModel :: Serializers :: XML
attr_accessor :user , :article , :content , :created_at , :updated_at
def attributes
{
"user" => @user ,
"article" => @article ,
"content" => @content ,
"created_at" => @created_at ,
"updated_at" => @updated_at ,
}
end
def attributes = ( hash )
hash . each do | key , value |
instance_variable_set ( "@ #{ key } " , value )
end
end
end
A c t i v e M o d e l : : S e r i a l i z e r : : J S O N が 提 供 す る f r o m _ j s o n
お よ び t o _ j s o n
メ ソ ッ ド を 使 う 場 合 は 、 a t t r i b u t e s
メ ソ ッ ド と a t t r i b u t e s
= ( h a s h )
メ ソ ッ ド を 定 義 す る 必 要 が あ り ま す 。
A c t i v e M o d e l : : V a l i d a t i o n s
A c t i v e M o d e l : : V a l i d a t i o n s を 使 う と 、 A c t i v e R e c o r d で 利 用 で き る の と ほ ぼ 同 じ バ リ デ ー シ ョ ン の 機 能 が 使 え る よ う に な り ま す 。 た だ し 、 一 部 デ ー タ ベ ー ス に デ ー タ が 保 存 さ れ て い る 前 提 の 機 能 は A c t i v e R e c o r d : : V a l i d a t i o n s に 定 義 さ れ て い ま す の で 、 A c t i v e M o d e l : : V a l i d a t i o n s で す べ て A c t i v e R e c o r d の バ リ デ ー シ ョ ン と 同 じ 機 能 が 使 え る わ け で は あ り ま せ ん 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Article
include ActiveModel :: Validations
include ActiveModel :: Validations :: Callbacks
attr_accessor :author , :category , :url , :title , :content , :created_at , :updated_at
validates_presence_of :author
validates :url , presence : true , format : { with : /\A[-_a-z0-9]*\z/ }
before_save :set_title , unless :title?
private
def set_title
self . title = url . gsub ( /[^a-z0-9]+/ , " " ) . split ( " " ) . map ( & :capitalize ) . join ( " " )
end
end
A c t i v e M o d e l : : V a l i d a t i o n s で 使 え る よ う に な る バ リ デ ー シ ョ ン は 以 下 で す 。
● v a l i d a t e s _ a b s e n c e _ o f
● v a l i d a t e s _ a c c e p t a n c e _ o f
● v a l i d a t e s _ c o n f i r m a t i o n _ o f
● v a l i d a t e s _ e x c l u s i o n _ o f
● v a l i d a t e s _ f o r m a t _ o f
● v a l i d a t e s _ i n c l u s i o n _ o f
● v a l i d a t e s _ l e n g t h _ o f
● v a l i d a t e s _ n u m e r i c a l i t y _ o f
● v a l i d a t e s _ p r e s e n c e _ o f
● v a l i d a t e s _ s i z e _ o f
な お 、 b e f o r e _ v a l i d a t i o n
な ど の コ ー ル バ ッ ク を 使 う 場 合 は 別 途 A c t i v e M o d e l : : V a l i d a t i o n s : : C a l l b a c k s の i n c l u d e が 必 要 で す 。
A c t i v e M o d e l : : M o d e l
A c t i v e M o d e l : : M o d e l は R a i l s 4 か ら 追 加 さ れ た モ ジ ュ ー ル で 、 こ れ を i n c l u d e す る と 以 下 の モ ジ ュ ー ル を 一 括 で i n c l u d e し て よ り シ ン プ ル な 記 述 で A c t i v e R e c o r d ラ イ ク な 挙 動 を 与 え る こ と が で き る よ う に な り ま す 。
● A c t i v e M o d e l : : N a m i n g
● A c t i v e M o d e l : : T r a n s l a t i o n
● A c t i v e M o d e l : : V a l i d a t i o n s
● A c t i v e M o d e l : : C o n v e r s i o n
A c t i v e M o d e l : : M o d e l を i n c l u d e し た ク ラ ス は R a i l s の フ ォ ー ム ヘ ル パ ー な ど に 引 数 と し て 渡 す た め に 必 要 な 振 る 舞 い を 簡 単 に 満 た せ ま す 。 そ の た め 、 デ ー タ ベ ー ス に 依 存 し な い 入 力 フ ォ ー ム な ど を 構 築 し た い と き や 、 複 数 の A c t i v e R e c o r d オ ブ ジ ェ ク ト に ま た が る 情 報 を ま と め て 扱 い た い と き な ど に 便 利 と い う こ と で す 。
エ ン テ ィ テ ィ と 値 オ ブ ジ ェ ク ト
ア プ リ ケ ー シ ョ ン が 扱 う オ ブ ジ ェ ク ト は 、 同 一 性 を ど う 捉 え る か に よ っ て 種 類 に わ け ら れ ま す 。
種類
意味
例
エンティティ
システムにおいてオブジェクトの同一性が重要な意味を持つもの。Rails のモデルが持つ id
のような識別情報を持つ。識別情報が同じなら同じエンティティ
User(id, login_id, name, email, address)
クラスのオブジェクト
値オブジェクト
「何である」かが重要で、値が同じであればアプリケーション上は同一とみなしていいもの。オブジェクトが持つ値が同じかどうかが同一性を決める
メールアドレス、住所
ActiveRecord オブジェクトは基本的にはエンティティですが、その属性値の中には値オブジェクトとして扱うと便利なものもあります。
例えば以下のような、名前と(なぜか)和暦の日付を管理する Holiday クラスがあったとします(ねーよw)。日付は年号 era_name
と年月日から成ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# == Schema Information
#
# Table name: holidays
#
# id :integer not null, primary key
# name :string(255)
# era_name :string(255)
# year :integer
# month :integer
# day :integer
# created_at :datetime
# updated_at :datetime
#
class Holiday < ActiveRecord :: Base
def same_date? ( other )
return false unless other
same_era_name? ( other ) && same_year? ( other ) && same_month? ( other ) && same_day? ( other )
end
private
def same_era_name? ( other )
era_name == other . era_name
end
def same_year? ( other )
year == other . year
end
def same_month? ( other )
month == other . month
end
def same_day? ( other )
day == other . day
end
end
日付が同じかどうかを判別する機能を Holiday クラスに直接実装すると、↑のコードように Holiday クラスが持つ責任範囲が広くなりすぎてしまいます。また、例えば誕生日(Birthday)など他のクラスにも日付を持つオブジェクトが存在するかもしれません。
このような場合、値オブジェクトとして日付を表現すると便利です。
1
2
3
4
5
6
7
8
9
10
11
12
13
class Holiday < ActiveRecord :: Base
def date
@date ||= JapaneseCalendarDate . new ( era_name , year , month , day )
end
def date = ( date )
self . era_name = date . era_name
self . year = date . year
self . month = date . month
self . day = date . day
@date = date
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class JapaneseCalendarDate
attr_accessor :era_name , :year , :month , :day
def initialize ( era_name = nil , year = nil , month = nil , day = nil )
@era_name = era_name
@year = year
@month = month
@day = day
end
def hash
era_name . hash + year . hash + month . hash + day . hash
end
def == ( other )
return false unless other . kind_of? ( JapaneseCalendarDate )
same_era_name? ( other ) && same_year? ( other ) && same_month? ( other ) && same_day? ( other )
end
private
def same_era_name? ( other )
era_name == other . era_name
end
def same_year? ( other )
year == other . year
end
def same_month? ( other )
month == other . month
end
def same_day? ( other )
day == other . day
end
end
このように値オブジェクトを使うことで、JapaneseCalendarDate というコンパクトな範囲に責任を限定し、実装を適切な場所に移すことができました。もし日付を扱うクラスが増えても同じ実装を再利用すれば OK です。
値オブジェクトは、責任を適切に分割することに加えて、業務知識の語彙を実装にマッピングする点でも意味があります。これにより実装と業務知識のモデルの差を小さくできます。
なお、Rails では compose_of
メソッドを使うことで簡単に値オブジェクトを扱うことができます。さきほどの Holiday クラスの例では以下のような実装になります。
1
2
3
class Holiday < ActiveRecord :: Base
compose_of :japanese_calendar_date , mapping : [ %w[era_name era_name] , %w[year year] , %w[month month] , %w[day day] ]
end
compose_of
はいくつかオプションをとれます。本書には各オプションの解説と以下のような IP アドレスの例も載っています。
1
2
3
4
5
compose_of :ip_address ,
class_name : "IPAddr" ,
mapping : %w[ip to_i] ,
constructor : Proc . new { | ip | IPAddr . new ( ip , Socket :: AF_INET ) },
converter : Proc . new { | ip | ip . is_a? ( Integer ) ? IPAddr . new ( ip , Socket :: AF_INET ) : IPAddr . new ( ip . to_s ) }
c o m p o s e _ o f
を 使 う と 宣 言 的 に 記 述 で き る と い う メ リ ッ ト が あ り ま す が 、 オ プ シ ョ ン が 複 雑 で わ か り づ ら い と い う デ メ リ ッ ト も あ り ま す 。 そ の よ う な 場 合 は 素 直 に 自 分 で 定 義 し た ほ う が い い で し ょ う 。
C o n c e r n : 関 心 事 の 分 離
R a i l s 4 か ら 追 加 さ れ た a p p / m o d e l s / c o n c e r n s や a p p / c o n t r o l l e r s / c o n c e r n s と い っ た デ ィ レ ク ト リ は 、 開 発 者 の 関 心 事 を ま と め た モ ジ ュ ー ル ︵ C o n c e r n モ ジ ュ ー ル ︶ を 配 置 す る こ と が 期 待 さ れ て い ま す 。
あ る 機 能 を 実 現 す る た め に 必 要 な 処 理 を C o n c e r n モ ジ ュ ー ル と し て 分 離 す る こ と で 、 モ デ ル や コ ン ト ロ ー ラ か ら 特 定 の 機 能 の た め に の み 利 用 さ れ る メ ソ ッ ド や バ リ デ ー シ ョ ン の 実 装 を 分 離 で き ま す 。 も し こ の 機 能 に 変 更 が 生 じ た と し て も 、 そ の 影 響 範 囲 を 想 定 し や す く な り ま す 。
A c t i v e R e c o r d を 拡 張 す る プ ラ グ イ ン や 特 定 の 機 能 を 提 供 す る g e m は た く さ ん あ り ま す が 、 ア プ リ ケ ー シ ョ ン 特 有 の 機 能 を 追 加 し た り 、 外 部 の g e m に ロ ッ ク イ ン さ れ る の を 避 け た り と い っ た と き に は C o n c e r n を 使 う と 便 利 で す 。
A c t i v e S u p p o r t : : C o n c e r n
R a i l s 内 部 で も 使 わ れ て い る A c t i v e S u p p o r t : : C o n c e r n は C o n c e r n に 関 連 し た 記 述 を 補 助 し て く れ ま す 。 例 え ば 、
●
i n c l u d e d
メ ソ ッ ド に ブ ロ ッ ク を 渡 す 機 能 を 追 加 す る 。 i n c l u d e さ れ た と き に フ ッ ク し て 実 行 す る 処 理 を 直 感 的 に 記 述 で き る
● ク ラ ス メ ソ ッ ド を 追 加 す る た め の 記 述 を 補 助
● モ ジ ュ ー ル の 依 存 関 係 を 管 理 す る
と い っ た 機 能 で す 。 個 人 的 に は 、 特 に 最 後 の 依 存 関 係 の 管 理 機 能 が 便 利 だ と 思 っ て い ま す ︵ 自 前 実 装 で ハ マ っ た 経 験 あ り o r z ︶ 。
A c t i v e S u p p o r t : : C o n c e r n に あ る 例 を 見 る と 機 能 が よ く わ か る と 思 い ま す 。 リ ン ク 先 で は 依 存 関 係 の と こ ろ は さ ら っ と 流 し て い ま す が 、 本 書 で は 詳 し く 解 説 さ れ て い ま す 。
ま た 本 書 に は 以 下 も 詳 し く 載 っ て い ま す の で 、 理 解 を 深 め た い 人 や 実 例 が 見 た い と い う 人 は 一 見 の 価 値 あ り だ と 思 い ま す 。
● A c t i v e S u p p o r t : : C o n c e r n が ど の よ う な 仕 組 み で こ れ ら の 機 能 を 実 現 し て い る か
● A c t i v e S u p p o r t : : C o n c e r n を 使 っ た 論 理 削 除 機 能 の 実 装 例
● バ ス の 配 車 ス ケ ジ ュ ー ル を 管 理 す る ア プ リ ケ ー シ ョ ン で ﹁ 予 約 ﹂ と ﹁ 予 約 希 望 ﹂ が 持 つ 共 通 の 振 る 舞 い を C o n c e r n モ ジ ュ ー ル に 分 離 し た 話
M o d u l e # c o n c e r n i n g
R a i l s 4 . 1 で 追 加 さ れ た M o d u l e # c o n c e r n i
n g
を 使 う と イ ン ラ イ ン モ ジ ュ ー ル を 簡 単 に 記 述 で き ま す 。
1
2
3
4
5
6
7
8
9
class User < ActiveRecord :: Base
concerning :Segment do
included do
scope :male , -> { where ( sex : "male" ) }
scope :female , -> { where ( sex : "female" ) }
scope :young , -> { where ( "age < ?" , 20 ) }
end
end
end
M o d u l e # c o n c e r n i n g
の 主 な 用 途 は c o n c e r n i n g メ ソ ッ ド が 定 義 し て あ る ソ ー ス コ ー ド に コ メ ン ト と し て 書 い て あ り ま す 。 ざ っ く り ま と め る と 以 下 の よ う な 感 じ で す 。
● ク ラ ス が 大 き く な っ て く る と 、 特 定 の 関 心 事 と し て 切 り 出 せ る よ う な 関 連 性 の あ る 処 理 / 振 る 舞 い が 出 て く る
● 場 合 に よ っ て は 、 別 フ ァ イ ル に 切 り 出 す ほ ど で は な い ︵ 切 り 出 す と 逆 に 読 み づ ら く な る ︶ と い う こ と が あ る
● ク ラ ス 内 で m o d u l e H o g e ; . . . . ; e n d ; i
n c l u d e H o g e
と す れ ば 、 ま と ま り と し て 切 り 出 し て 見 通 し が よ く な る
●
M o d u l e # c o n c e r n i n g
を 使 う こ と で 、 切 り 出 し た と き の 本 質 的 で な い コ ー ド を 減 ら し て 簡 潔 に 記 述 で き る
サ ー ビ ス ク ラ ス
1 つ の 機 能 を 完 結 さ せ る た め に 非 常 に 複 雑 な 処 理 が 必 要 に な っ た り 、 特 定 の エ ン テ ィ テ ィ や 値 オ ブ ジ ェ ク ト に 所 属 さ せ る と 不 自 然 に な っ て し ま う 処 理 が 出 て き た り し た と き は 、 ﹁ サ ー ビ ス ﹂ と い う 概 念 を 使 う と 有 効 な 場 合 が あ り ま す 。 一 連 の 処 理 を サ ー ビ ス ク ラ ス に 抽 出 す る こ と で 、 モ デ ル が 過 剰 に 複 雑 に な る こ と を 防 ぐ こ と が で き ま す 。
本 書 で 紹 介 さ れ て い る サ ー ビ ス ク ラ ス の 特 徴 は 以 下 の よ う な も の で す 。
● R a i l s の 世 界 で 考 え た 場 合 、 コ ン ト ロ ー ラ と モ デ ル の 中 間 の よ う な 存 在 。 コ ン ト ロ ー ラ が ユ ー ザ か ら の リ ク エ ス ト を 呼 び 出 す イ ン タ ー フ ェ イ ス で 、 サ ー ビ ス が モ デ ル が 行 う 処 理 を と り ま と め て 実 行 す る た め の イ ン タ ー フ ェ イ ス
● 処 理 そ の も の を カ プ セ ル 化 し 責 務 を 分 離 し た も の
● ﹁ 認 証 サ ー ビ ス ﹂ や ﹁ 価 格 計 算 サ ー ビ ス ﹂ な ど の 機 能 や 振 る 舞 い そ の も の を 表 す 名 前 を 持 つ
● 適 切 に 設 計 さ れ た サ ー ビ ス ク ラ ス は 基 本 的 に 状 態 を 持 た な い 。 入 力 が 同 じ な ら 同 一 の 結 果 を 返 す
● 業 務 知 識 と 実 装 の メ ン タ ル モ デ ル を 一 致 さ せ る 。 シ ス テ ム が 対 象 と し て い る 業 務 領 域 の 知 識 と 照 ら し 合 わ せ て 、 よ り 自 然 な 形 で ア プ リ ケ ー シ ョ ン を 設 計 す る た め の 手 段
● シ ス テ ム が 対 象 と し て い る 業 務 に 結 び つ い た 名 前 付 け が で き て い な い 場 合 、 サ ー ビ ス ク ラ ス を 利 用 す る 対 象 と し て は 不 適 切 な 可 能 性 が あ る
サ ー ビ ス ク ラ ス の 例 と し て よ く 挙 げ ら れ る の が 銀 行 口 座 間 の 振 替 処 理 の 実 装 で す 。 本 書 で は こ の 例 を R a i l s で 実 装 し た ら … … と い う こ と で サ ー ビ ス ク ラ ス の 解 説 を し て い ま す 。 考 え 方 自 体 は R u b y や R a i l s に 限 定 さ れ た 話 で は な い の で 、 本 書 の サ ン プ ル を 見 な く て も い い と 思 い ま す 。 本 書 で 見 る と す る と 、 サ ー ビ ス ク ラ ス 用 に a p p / s e r v i c e s デ ィ レ ク ト リ を 切 っ て a u t o l o a d _ p a t h s に 追 加 す る あ た り で し ょ う か 。
本 書 で は 実 装 例 を 示 し た 後 に 以 下 の よ う に サ ー ビ ス ク ラ ス を 利 用 す る メ リ ッ ト を 説 明 し て い ま す 。
● 複 数 の 役 割 を 持 つ エ ン テ ィ テ ィ が 登 場 し 、 そ れ を 1 つ の ト ラ ン ザ ク シ ョ ン と し て ま と め て 表 現 す る の が 自 然 な と き な ど に は サ ー ビ ス ク ラ ス が 有 効
● あ る モ デ ル に 直 接 実 装 し よ う と す る と 、 ト ラ ン ザ ク シ ョ ン の 起 点 を イ ン ス タ ン ス メ ソ ッ ド と し て 配 置 す る の は 不 自 然
● モ デ ル の ク ラ ス メ ソ ッ ド と し て 実 装 す る と 、 特 定 の 機 能 に の み 関 わ る 振 る 舞 い が ク ラ ス 全 体 で 必 要 な 振 る 舞 い で あ る か の よ う に 見 え て し ま う
● イ ン ス タ ン ス メ ソ ッ ド に し ろ ク ラ ス メ ソ ッ ド に し ろ モ デ ル に 直 接 実 装 す る と 、 機 能 が 増 え る に 従 っ て ど ん ど ん モ デ ル が 肥 大 化 す る
● 明 ら か に 業 務 知 識 を 表 す 振 る 舞 い な の で 、 コ ン ト ロ ー ラ に 実 装 し て し ま っ た ら 、 業 務 知 識 を モ デ ル 層 に 集 約 し て 変 更 に 対 す る 柔 軟 性 を 高 め る と い う レ イ ヤ ー ど う し の 独 立 性 を 失 う
そ し て 最 後 に 、 サ ー ビ ス ク ラ ス を 利 用 す る 際 の 注 意 点 に も 次 の よ う に 触 れ て い ま す 。
● 本 来 、 シ ス テ ム の 中 核 と な る ビ ジ ネ ス ロ ジ ッ ク は モ デ ル に 集 約 さ れ て い る の が 望 ま し い 。 サ ー ビ ス ク ラ ス を 濫 用 す る と 、 本 来 モ デ ル に あ る の が 自 然 な 振 る 舞 い ま で サ ー ビ ス ク ラ ス に 漏 れ 出 て し ま う
● サ ー ビ ス ク ラ ス は 処 理 や 振 る 舞 い を カ プ セ ル 化 し て い る た め 、 手 続 き 的 な 記 述 に な り が ち 。 同 じ よ う な 振 る 舞 い が 分 散 し て 実 装 さ れ 、 設 計 の 柔 軟 性 が 失 わ れ る 危 険 が あ る
● そ う な る と 振 る 舞 い の 再 利 用 性 が 低 下 し 、 最 終 的 に ア プ リ ケ ー シ ョ ン 全 体 の メ ン テ ナ ン ス 性 を 損 な う こ と に な る
● サ ー ビ ス は あ く ま で 処 理 の 大 枠 を 表 現 す る も の で あ り 、 よ り 詳 細 な レ ベ ル の 振 る 舞 い は 各 モ デ ル が 責 任 を 持 つ べ き
第 10 章 R a i l s を 拡 張 す る
R a c k M i d d l e w a r e と R a i l t i e を 自 分 で つ く り R a i l s を 拡 張 す る 方 法 に つ い て 書 か れ た 章 で す 。 以 下 、 本 書 に 書 か れ て い る 内 容 を 簡 単 に ま と め ま す 。 本 書 で は 豊 富 な サ ン プ ル コ ー ド と 詳 し い 解 説 が 書 か れ て い ま す 。
R a c k M i d d l e w a r e
R a c k と い う の は 、 ﹁ た く さ ん の ア プ リ ケ ー シ ョ ン サ ー バ と た く さ ん の R u b y フ レ ー ム ワ ー ク を つ な ぐ 規 約 ﹂ で す 。 P y t h o n の P S G I の 規 約 を 基 に 提 案 さ れ た そ う で す 。 以 下 の 規 約 に 準 拠 し て い れ ば 、 R a c k に 準 拠 し た ア プ リ ケ ー シ ョ ン で す 。
● 1 つ の H a s h オ ブ ジ ェ ク ト ︵ e n v ︶ を 引 数 に と る c a l l メ ソ ッ ド が あ る
● c a l l メ ソ ッ ド は ﹁ ス テ ー タ ス コ ー ド 、 ヘ ッ ダ ー を 表 現 し た H a s h 、 e a c h に 反 応 す る オ ブ ジ ェ ク ト ﹂ の 3 つ の 要 素 を 持 っ た 配 列 を 返 す
R a c k M i d d l e w a r e は 、 ﹁ R a c k に 対 応 し た ア プ リ ケ ー シ ョ ン に 機 能 を 追 加 す る た め の ミ ド ル ウ ェ ア の こ と ﹂ で す 。 以 下 の 特 徴 を 持 っ た ク ラ ス は R a c k M i d d l e w a r e と し て 利 用 で き ま す 。
● 別 の R a c k ア プ リ ケ ー シ ョ ン を 第 1 引 数 に と っ た i n i t i a l i z e メ ソ ッ ド が あ る
● R a c k ア プ リ ケ ー シ ョ ン と 同 様 、 e n v を と っ て 配 列 を 返 す c a l l メ ソ ッ ド が あ る
ru フ ァ イ ル 内 で u s e メ ソ ッ ド に こ の ク ラ ス を 渡 す こ と で R a c k M i d d l e w a r e を 利 用 し ま す 。 複 数 の u s e も 可 能 で す 。
R a i l s で R a c k M i d d l e w a r e を 使 う 場 合 は 、 c o n f i g / a p p l i c a t i o n . r b ま た は c o n f i g / e n v i r o n m e n t s / * . r b 内 で u s e メ ソ ッ ド を 呼 び 出 し ま す 。
config/application.rb
1
2
3
4
5
module AwesomeEvents
class Application < Rails :: Application
config . middleware . use AwesomeMiddleware
end
end
有名な Rack Middleware としては以下のようなものがあります。
名前
内容
Rack::Auth::Digest
Digest 認証をかける。Rack gem に標準添付
Rack::Cors
Cross-Origin Resource Sharing(ドメインをまたいだ Ajax リクエスト)を実現するために必要なヘッダーを追加してくれる
Rack::Rewrite
アクセスされた URL を別のものに変換する
OmniAuth
さまざまな外部認証の仕組みとの連携を Rack のレイヤーで済ませてしまう
Railtie
R a i l t i e と は 、 R a i l s 3 以 降 に 導 入 さ れ た 公 式 の プ ラ グ イ ン 機 構 で す 。 R a i l t i e の 仕 組 み を 使 う と 、 次 の よ う な 処 理 を 完 結 に 実 現 で き ま す ︵ 公 式 ド キ ュ メ ン ト ︶ 。
● 初 期 化 処 理 ︵ イ ニ シ ャ ラ イ ザ ︶ を 実 行 す る
● ジ ェ ネ レ ー タ や R a k e タ ス ク を R a i l s に 追 加 す る
● R a i l s の 設 定 項 目 を 追 加 し 、 e n v i r o n m e n t s ご と に カ ス タ マ イ ズ 可 能 に す る
● A c t i v e S u p p o r t : : N o t i f i c a t i o n s の た め の 固 有 の サ ブ ス ク ラ イ バ を 設 定 す る
R a i l t i e を 用 い た プ ラ グ イ ン の つ く り 方 に は 大 き く 3 パ タ ー ン の 方 法 が あ り ま す 。
型
特徴
例
Railtie 型
Railtie が提供する基本的な機能のみを利用する
Engine 型
Railtie 型に加えて独自のコントローラやルーティング、モデルなどを提供する
Devise 、Doorkeeper
Mountable Engine 型
Engine 型よりもさらに独立性の高いアプリケーションをプラグインとして提供する
RailsAdmin 、Refinery CMS
R a i l t i e 型 の プ ラ グ イ ン は r a i l s p l u g i n n e
w h o g e
で 雛 形 を つ く れ ま す 。
さ ら に l i b / h o g e / r a i l t i e . r b で 設 定 を 行 い ま す 。 本 書 の 例 で は ネ ー ム ス ペ ー ス を 切 っ て 設 定 項 目 を 追 加 す る の と 、 R a i l s の モ ジ ュ ー ル を 先 読 み す る 対 象 の リ ス ト で あ る e a g e r _
l o a d _ n a m e s p a c e s
へ の 追 加 を 行 っ て い ま す 。 R a i l s の コ ア ラ イ ブ ラ リ が 読 み 込 ま れ た あ と に 走 る べ き 処 理 は i n i t
i a l i z e r
と い う ブ ロ ッ ク を 用 い て 定 義 し ま す 。 A c t i v e S
u p p o r t . o n _ l o a d
ブ ロ ッ ク を 使 う と 、 R a i l s の 各 コ ア コ ン ポ ー ネ ン ト の 読 み 込 み に フ ッ ク し て 実 行 さ れ る べ き 処 理 内 容 を 記 述 で き ま す 。
E n g i n e 型 の プ ラ グ イ ン は r a i l s p l u g i n n e w
h o g e - - f u l l
の よ う に - - f u l l
オ プ シ ョ ン を つ け る こ と で 雛 形 を つ く れ ま す 。
さ ら に 以 下 の よ う な l i b / h o g e / e n g i n e . r b を つ く れ ば OK で す 。
lib/hoge/engine.rb
1
2
3
4
module Hoge
class Engine < :: Rails :: Engine
end
end
M o u n t a b l e E n g i n e 型 の プ ラ グ イ ン は r a i l s
p l u g i n n e w h o g e - - m o u n t a b l e
の よ う に - - m o u n t a b l e
オ プ シ ョ ン を つ け る こ と で 雛 形 を つ く れ ま す 。
さ ら に E n g i n e 型 と 似 て い ま す が 以 下 の よ う な E n g i n e フ ァ イ ル を つ く り ま す 。 H o g e 以 下 の ネ ー ム ス ペ ー ス に 定 義 さ れ た ア プ リ を 独 立 し た R a i l s ア プ リ ケ ー シ ョ ン と し て 利 用 す る と い う 意 味 で す 。
1
2
3
4
5
module Hoge
class Engine < :: Rails :: Engine
isolate_namespace Hoge
end
end
コントローラなども app/controllers/hoge/*_controller.rb のようにネームスペース以下に生成されます。
他の Rails アプリで使う場合、config/routes.rb で以下のように mount 宣言をします。
1
mount Hoge :: Engine => "/status"