Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
567
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.55 KB | None | 0 0
  1. # 学習用メモ
  2. ***
  3. ## 6章.ユーザーのモデルを作成する
  4.  
  5. ### 理解できたもの
  6.  
  7. この章では、一番重要なステップであるユーザー用のデータモデルの作成と、データを保存する手段の確保について学んでいく。
  8.  
  9. *Userモデル*
  10.  
  11. 今のままでは新しいユーザーの情報を受け取っても保存する場所がないので、いきなりページを作成するわけには行かない。ユーザー登録でまず初めにやることは、それらの情報を保存するためのデータ構造を作成すること。
  12.  
  13. Railsでは、データモデルで使用するデフォルトのデータ構造のことをモデルと呼ぶ。Railsでは、データを永続化するデフォルトの解決策として、データベースを使用してデータを長期間保存する。また、データベースとやりとりするデフォルトのRailsライブラリはActive Recordと呼ばれる。Active Recordは、データオブジェクトの作成/保存/検索のためのメソッドを持っている。
  14.  
  15. さらに、Railsにはマイグレーションという機能がある。データの定義をRubyで記述することができ、SQLのDDL (Data Definition Language)を新たに学ぶ必要がない。
  16.  
  17. *ユーザーをモデリングするためのトピックブランチを作成する。*
  18.  
  19. ```
  20. $ git checkout master
  21. $ git checkout -b modeling-users
  22. ```
  23.  
  24. *データベースの移行*
  25.  
  26. この節での目的は、簡単に消えることのないユーザのモデルを構築すること。
  27.  
  28. nameとemailの2つの属性からなるユーザーをモデリングするところから始める。後者のemailを一意のユーザー名として使用する。
  29.  
  30. Railsでユーザーをモデリングするときは、属性を明示的に識別する必要がない。上で述べたように、Railsはデータを保存する際にデフォルトでリレーショナルデータベースを使用する。リレーショナルデータベースは、データ行で構成されるテーブルからなり、各行はデータ属性のカラム (列) を持つ。たとえば、nameとemailを持つユーザーを保存するのであれば、nameとemailのカラムを持つusersテーブルを作成する。
  31.  
  32. ユーザーコントローラを作成した時は以下のコマンドを使った。
  33.  
  34. ```
  35. $ rails generate controller Users new
  36. ```
  37.  
  38. モデルを作成するときは、上と似たようなパターンでgenerate modelというコマンドを使う。さらに、今回はnameやemailといった属性を付けたUserモデルを使いたいので、実際に打つコマンドは以下になる。
  39.  
  40. *Userモデルを生成する*
  41.  
  42. ```
  43. $ rails generate model User name:string email:string
  44. invoke active_record
  45. create db/migrate/20140724010738_create_users.rb
  46. create app/models/user.rb
  47. invoke test_unit
  48. create test/models/user_test.rb
  49. create test/fixtures/users.yml
  50. ```
  51.  
  52.  
  53. *コントローラ名には複数形を使い、モデル名には単数形を用いるという慣習を頭に入れておく。コントローラはUsersでモデルはUser*
  54.  
  55. name:stringやemail:stringオプションのパラメータを渡すことによって、データベースで使用したい2つの属性をRailsに伝える。このときに、これらの属性の型情報も一緒に渡す。
  56.  
  57.  
  58. generateコマンドの結果のひとつとして、マイグレーションと呼ばれる新しいファイルが生成される。マイグレーションは、データベースの構造をインクリメンタルに変更する手段を提供する。それにより、要求が変更された場合にデータモデルを適合させることができる。このUserモデルの例の場合、マイグレーションはモデル生成スクリプトによって自動的に作られる。
  59.  
  60. 以下のようにnameとemailの2つのカラムを持つuserテーブルを作成する。
  61.  
  62. *usersテーブルを作るためのUserモデルのマイグレーション*
  63.  
  64. ```
  65. db/migrate/[timestamp]_create_users.rb
  66. class CreateUsers < ActiveRecord::Migration
  67. def change
  68. create_table :users do |t|
  69. t.string :name
  70. t.string :email
  71.  
  72. t.timestamps null: false
  73. end
  74. end
  75. end
  76. ```
  77.  
  78. マイグレーションファイル名の先頭には、それが生成された時間のタイムスタンプが追加される。これによって、複数のプログラマが同じ整数を持つマイグレーションファイルの生成するというコンンフリクトを避けられる。
  79.  
  80. イグレーション自体は、データベースに与える変更を定義したchangeメソッドの集まり
  81.  
  82. 上のコードの場合、changeメソッドはcreate_tableというRailsのメソッドを呼び、ユーザーを保存するためのテーブルをデータベースに作成する。create_tableメソッドはブロック変数を1つ持つブロックを受け取る。ここでは (“table”の頭文字を取って) t。そのブロックの中でcreate_tableメソッドはtオブジェクトを使って、nameとemailカラムをデータベースに作る。型はどちらもstringです4。モデル名は単数形 (User) だが、テーブル名は複数形 (users)。これはRailsで用いられる言葉の慣習を反映している。モデルはひとりのユーザーを表すのに対し、データベースのテーブルは複数のユーザーから構成される。ブロックの最後の行t.timestampsは特別なコマンドで、created_atとupdated_atという2つの「マジックカラム」を作成する。これらは、あるユーザーが作成または更新されたときに、その時刻を自動的に記録するタイムスタンプ。
  83.  
  84. マイグレーションは、以下のようにrakeコマンドを使って実行することができる。これを「マイグレーションの適用 (migrating up)」と呼ぶ。
  85.  
  86. ```
  87. $ bundle exec rake db:migrate
  88. ```
  89.  
  90. 初めてdb:migrateが実行されると、db/development.sqlite3という名前のファイルが生成される。。これはSQLite5データベース。
  91.  
  92. Railsチュートリアルで使用されているものすべてを含め、ほとんどのマイグレーションが可逆。これは、db:rollbackというRakeタスクで変更を取り消せることを意味する。これを“マイグレーションの取り消し (migrate down) と呼ぶ。
  93.  
  94. ```
  95. $ bundle exec rake db:rollback
  96. ```
  97.  
  98. *modelファイル*
  99.  
  100. Userモデルの作成によってどのようにマイグレーションファイルが作成されるかを見てきた。そしてこのマイグレーションを実行した結果を見た。
  101.  
  102. また、モデル用のuser.rbも作られた。ここでは、このモデル用ファイルを理解することに専念する。
  103.  
  104. まずは、app/models/ディレクトリにある、user.rbファイルに書かれたUserモデルのコードを見てみる。
  105.  
  106. *生成されたばかりのUserモデル*
  107.  
  108. ```
  109. app/models/user.rb
  110. class User < ActiveRecord::Base
  111. end
  112. ```
  113.  
  114. class User < ActiveRecord::Baseという構文で、UserクラスはActiveRecord::Baseを継承するので、Userモデルは自動的にActiveRecord::Baseクラスのすべての機能を持つ。
  115.  
  116. *ユーザーオブジェクトを作成する*
  117.  
  118. Railsコンソールを使用してデータモデルを調べてみる。現時点ではデータベースを変更したくないので、コンソールをサンドボックスモード(ここで行われた変更は終了時にロールバッkされる)で起動。
  119.  
  120. ```
  121. $ rails console --sandbox
  122. Loading development environment in sandbox
  123. Any modifications you make will be rolled back on exit
  124. >>
  125. ```
  126.  
  127. モデルを使う場合。Railsコンソールは起動時にRailsの環境を自動的に読み込むため、その環境にはモデルも含まれます。つまり、新しいユーザーオブジェクトを作成するときに余分(ファイルを明示的にrequireする)な作業を行わずに済む。
  128.  
  129. ```
  130. >> User.new
  131. => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
  132. ```
  133.  
  134. User.newを引数なしで呼んだ場合は、すべての属性がnilのオブジェクトを返す。
  135.  
  136. 以下のように引数を持たせると
  137.  
  138. ```
  139. >> user = User.new(name: "Michael Hartl", email: "mhartl@example.com")
  140. => #<User id: nil, name: "Michael Hartl", email: "mhartl@example.com",
  141. created_at: nil, updated_at: nil>
  142. ```
  143.  
  144. nameとemail属性が期待どおり設定されていることがわかる。
  145.  
  146. Active Recordを理解する上で、「有効性 (Validity)」という概念も重要。まず先ほどのuserオブジェクトが有効かどうか確認してみる。確認するためにはvalid?メソッドを使う。
  147.  
  148. ```
  149. >> user.valid?
  150. true
  151. ```
  152.  
  153. 現時点ではまだデータベースにデータは格納されていない。User.newはメモリ上でオブジェクトを作成しただけで、user.valid?という行はただオブジェクトが有効かどうかを確認しただけ。
  154.  
  155. データベースにUserオブジェクトを保存するためには、userオブジェクトからsaveメソッドを呼び出す必要がある。
  156.  
  157. ```
  158. >> user.save
  159. (0.2ms) begin transaction
  160. User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users".
  161. "email") = LOWER('mhartl@example.com') LIMIT 1
  162. SQL (0.5ms) INSERT INTO "users" ("created_at", "email", "name", "updated_at)
  163. VALUES (?, ?, ?, ?) [["created_at", "2014-09-11 14:32:14.199519"],
  164. ["email", "mhartl@example.com"], ["name", "Michael Hartl"], ["updated_at",
  165. "2014-09-11 14:32:14.199519"]]
  166. (0.9ms) commit transaction
  167. => true
  168. ```
  169.  
  170. saveメソッドは、成功すればtrueを、失敗すればfalseを返す。
  171.  
  172. 作成した時点でのユーザーオブジェクトは、id属性、マジックカラムであるcreated_at属性とupdated_at属性の値がいずれもnilであった。
  173.  
  174. saveメソッドを実行されたことで、idには1という値が代入され、一方でマジックカラムには現在の日時が代入されているのがわかる。
  175.  
  176. Userモデルのインスタンスはドット記法を用いてその属性にアクセスすることができる。
  177.  
  178. ```
  179. >> user.name
  180. => "Michael Hartl"
  181. >> user.email
  182. => "mhartl@example.com"
  183. >> user.updated_at
  184. => Thu, 24 Jul 2014 00:57:46 UTC +00:00
  185. ```
  186.  
  187. 上で見たようにモデルの生成と保存を2つのステップに分けておくと何かと便利。しかし、Active RecordではUser.createでモデルの生成と保存を同時におこなう方法も提供されている。
  188.  
  189. ```
  190. >> User.create(name: "A Nother", email: "another@example.org")
  191. #<User id: 2, name: "A Nother", email: "another@example.org", created_at:
  192. "2014-07-24 01:05:24", updated_at: "2014-07-24 01:05:24">
  193. >> foo = User.create(name: "Foo", email: "foo@bar.com")
  194. #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2014-07-24
  195. 01:05:42", updated_at: "2014-07-24 01:05:42">
  196. ```
  197.  
  198. destroyはcreateの逆で削除する。
  199.  
  200. ```
  201. >> foo.destroy
  202. => #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2014-07-24
  203. 01:05:42", updated_at: "2014-07-24 01:05:42">
  204. ```
  205.  
  206. estroyはそのオブジェクト自身を返すが、その返り値を使用しても、もう一度destroyを呼ぶことはできない。さらに、削除されたオブジェクトは、以下のようにまだメモリ上に残っている。
  207.  
  208. ```
  209. >> foo
  210. => #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2014-07-24
  211. 01:05:42", updated_at: "2014-07-24 01:05:42">
  212. ```
  213.  
  214. では、オブジェクトが本当に削除されたかどうかをどのようにして知ればよいのか。そして、保存して削除されていないオブジェクトの場合、どうやってデータベースからユーザーを取得するのでしょうか。これらの問いに答えるためには、Active Recordを使ってUserオブジェクトを検索する方法について学ぶ必要がある。
  215.  
  216. *ユーザオブジェクトを検索する*
  217.  
  218. Active Recordには、オブジェクトを検索するための方法がいくつもある。これらの機能を使用して、過去に作成した最初のユーザーを探してみる。
  219.  
  220. また、3番目のユーザー (foo) が削除されていることを確認する。まずは存在するユーザーから探してみる。
  221.  
  222. ```
  223. >> User.find(1)
  224. => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com",
  225. created_at: "2014-07-24 00:57:46", updated_at: "2014-07-24 00:57:46">
  226. ```
  227.  
  228. User.findにユーザーのidを渡しています。その結果、Active Recordはそのidのユーザーを返す。
  229.  
  230. id=3のユーザーがまだデータベースに存在するかどうかを確認。
  231.  
  232. ```
  233. >> User.find(3)
  234. ActiveRecord::RecordNotFound: Couldn't find User with ID=3
  235. ```
  236.  
  237. この場合見つからないので例外が起こる。
  238.  
  239. 一般的なfindメソッド以外に、Active Recordには特定の属性でユーザーを検索する方法もある。
  240.  
  241. ```
  242. >> User.find_by(email: "mhartl@example.com")
  243. => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com",
  244. created_at: "2014-07-24 00:57:46", updated_at: "2014-07-24 00:57:46">
  245. ```
  246.  
  247. そのほかにもfirstメソッド。
  248.  
  249. ```
  250. >> User.first
  251. => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com",
  252. created_at: "2014-07-24 00:57:46", updated_at: "2014-07-24 00:57:46">
  253. ```
  254.  
  255. firstは単にデータベースの最初のユーザーを返す。
  256.  
  257. allメソッド。
  258.  
  259. ```
  260. >> User.all
  261. => #<ActiveRecord::Relation [#<User id: 1, name: "Michael Hartl",
  262. email: "mhartl@example.com", created_at: "2014-07-24 00:57:46",
  263. updated_at: "2014-07-24 00:57:46">, #<User id: 2, name: "A Nother",
  264. email: "another@example.org", created_at: "2014-07-24 01:05:24",
  265. updated_at: "2014-07-24 01:05:24">]>
  266. ```
  267.  
  268. User.allでデータベースのすべてのUserオブジェクトが返ってくることがわかる。また、返ってきたオブジェクトのクラスが ActiveRecord::Relationとなっている。これは、各オブジェクトを配列として効率的にまとめてくれるクラス。
  269.  
  270. *ユーザーオブジェクトを更新する*
  271.  
  272. 基本的な更新の方法は2つ。ひとつは、属性を個別に代入する方法。
  273.  
  274. ```
  275. >> user # Just a reminder about our user's attributes
  276. => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com",
  277. created_at: "2014-07-24 00:57:46", updated_at: "2014-07-24 00:57:46">
  278. >> user.email = "mhartl@example.net"
  279. => "mhartl@example.net"
  280. >> user.save
  281. => true
  282. ```
  283.  
  284. 変更をデータベースに保存するために最後にsaveを実行する必要がある。保存を行わずにreloadを実行すると、データベースの情報を元にオブジェクトを再読み込みするので、以下のように変更が取り消される。
  285.  
  286. ```
  287. >> user.email
  288. => "mhartl@example.net"
  289. >> user.email = "foo@bar.com"
  290. => "foo@bar.com"
  291. >> user.reload.email
  292. => "mhartl@example.net"
  293. ```
  294.  
  295. user.saveを実行したことでユーザーが更新できた。マジックカラムの更新日時も更新されている。
  296.  
  297. ```
  298. >> user.created_at
  299. => "2014-07-24 00:57:46"
  300. >> user.updated_at
  301. => "2014-07-24 01:37:32"
  302. ```
  303.  
  304. 属性を更新するもうひとつの方法は、update_attributesを使う。
  305.  
  306. ```
  307. >> user.update_attributes(name: "The Dude", email: "dude@abides.org")
  308. => true
  309. >> user.name
  310. => "The Dude"
  311. >> user.email
  312. => "dude@abides.org"
  313. ```
  314.  
  315. update_attributesメソッドは属性のハッシュを受け取り、成功時には更新と保存を続けて同時に行う (保存に成功した場合はtrueを返す)。ただし、検証に1つでも失敗すると、update_attributesの呼び出しは失敗する。
  316.  
  317. #### ユーザーを検証する
  318.  
  319. nameとemailにあらゆる文字列を許すのは避けるべき。これらの属性値には、何らかの制約を与える必要がある。
  320.  
  321. Active Record では検証 (Validation) という機能を通して、こういった制約を課すことができるようになっている。
  322.  
  323. + 存在性 (presence)の検証
  324. + 長さ (length)の検証
  325. + フォーマット (format)の検証
  326. + 一意性 (uniqueness)の検証
  327.  
  328. *有効性のテスト*
  329.  
  330. モデルのバリデーション機能は、テスト駆動開発とまさにピッタシの機能と言える。
  331.  
  332. *具体的なテスト方法*
  333.  
  334. まず有効なモデルのオブジェクトを作成し、その属性のうちの1つを有効でない属性に意図的に変更する。そして、バリデーションで失敗するかどうかをテストする、といった方針で進めていく。念のため、最初に作成時の状態に対してもテストを書いておき、最初のモデルが有効であるかどうかも確認しておく。このようにテストすることで、バリデーションのテストが失敗したとき、バリデーションの実装に問題があったのか、オブジェクトそのものに問題があったのかを確認することができる。
  335.  
  336. まずはUser用テストの中身から見ていく。
  337.  
  338. *デフォルトのUserテスト (モックのみ)*
  339.  
  340. ```
  341. test/models/user_test.rb
  342. require 'test_helper'
  343.  
  344. class UserTest < ActiveSupport::TestCase
  345. # test "the truth" do
  346. # assert true
  347. # end
  348. end
  349. ```
  350.  
  351. ここに、有効なオブジェクトに対してテストを書くために、setupという特殊なメソッドを使って有効なUserオブジェクト(@user)を作成する。
  352.  
  353. setupメソッド内に書かれた処理は、書くテストが走る直前に実行される。@userはインスタンス変数だが、setupメソッド内で宣言しておけば、全てのテスト内でこのインンスタンス変数が使えるようになる。
  354.  
  355. したがって、valid?メソッドを使ってUserオブジェクトの有効性をテストすることができる。
  356.  
  357. *有効なUserかどうかをテストする*
  358.  
  359. ```
  360. GREEN
  361. test/models/user_test.rb
  362. require 'test_helper'
  363.  
  364. class UserTest < ActiveSupport::TestCase
  365.  
  366. def setup
  367. @user = User.new(name: "Example User", email: "user@example.com")
  368. end
  369.  
  370. test "should be valid" do
  371. assert @user.valid?
  372. end
  373. end
  374. ```
  375.  
  376. シンプルなassertメソッドを使ってテストする。@user.valid?がtrueを返すと成功し、falseを返すと失敗する。
  377.  
  378. まだバリデーションがないためこのテストは成功する。
  379.  
  380. ```
  381. $ bundle exec rake test:models
  382. ```
  383.  
  384. rake test:modelsというコマンドを実行してルガ、これはモデルに関するテストだけを走らせるコマンド。
  385.  
  386. *存在性を検証する*
  387.  
  388. 最も基本的なバリデーションは「存在性 (Presence)」。これは単に、与えられた属性が存在することを検証する。この節では、ユーザーがデータベースに保存される前にnameとemailフィールドの両方が存在することを保証する。
  389.  
  390. name属性の存在性に関するテストを追加する。
  391.  
  392. まず@user変数のname属性に対して空白の文字列をセットする。そして、assert_notメソッドを使って Userオブジェクトが有効でなくなったことを確認する。
  393.  
  394. *name属性にバリデーションに対するテスト*
  395.  
  396. ```
  397. RED
  398. test/models/user_test.rb
  399. require 'test_helper'
  400.  
  401. class UserTest < ActiveSupport::TestCase
  402.  
  403. def setup
  404. @user = User.new(name: "Example User", email: "user@example.com")
  405. end
  406.  
  407. test "should be valid" do
  408. assert @user.valid?
  409. end
  410.  
  411. test "name should be present" do
  412. @user.name = " "
  413. assert_not @user.valid?
  414. end
  415. end
  416. ```
  417.  
  418. この時点では、モデルのテストは失敗する。
  419.  
  420. name属性の存在を検査する方法は、validatesメソッドにpresence: trueという引数を与えて使う。presence: trueという引数は、要素がひとつのオプションハッシュである。
  421.  
  422. メソッドの最後の引数としてハッシュを渡す場合、波括弧を付けなくても問題ない。
  423.  
  424. *name属性の存在性を検証する*
  425.  
  426. ```
  427. GREEN
  428. app/models/user.rb
  429. class User < ActiveRecord::Base
  430. validates :name, presence: true
  431. end
  432. ```
  433.  
  434. コンソールを起動して、Userモデルに検証を追加した効果を見てみる。
  435.  
  436. ```
  437. $ rails console --sandbox
  438. >> user = User.new(name: "", email: "mhartl@example.com")
  439. >> user.valid?
  440. => false
  441. ```
  442.  
  443. user変数が有効かどうかをvalid?メソッドでチェックすることができる。もしオブジェクトがひとつ以上の検証に失敗したときは、falseを返す。 また、すべてのバリデーションに通ったときにtrueを返す。
  444.  
  445. どの検証が失敗したのかは。失敗した時に得られるerrorsオブジェクトを使って確認すればわかる。
  446.  
  447. ```
  448. >> user.errors.full_messages
  449. => ["Name can't be blank"]
  450. ```
  451.  
  452. Userオブジェクトは有効ではなくなったので、データベースに保存しようとすると自動的に失敗する。
  453.  
  454. ```
  455. >> user.save
  456. => false
  457. ```
  458.  
  459. この変更により、モデルのテストは成功する。
  460.  
  461. email属性の存在性についてもテストを書いてみる。
  462.  
  463. *email属性の検証に対するテスト*
  464.  
  465. ```
  466. RED
  467. test/models/user_test.rb
  468. require 'test_helper'
  469.  
  470. class UserTest < ActiveSupport::TestCase
  471.  
  472. def setup
  473. @user = User.new(name: "Example User", email: "user@example.com")
  474. end
  475.  
  476. test "should be valid" do
  477. assert @user.valid?
  478. end
  479.  
  480. test "name should be present" do
  481. @user.name = ""
  482. assert_not @user.valid?
  483. end
  484.  
  485. test "email should be present" do
  486. @user.email = " "
  487. assert_not @user.valid?
  488. end
  489. end
  490. ```
  491.  
  492. *email属性の存在性を検証する*
  493.  
  494. ```
  495. GREEN
  496. app/models/user.rb
  497. class User < ActiveRecord::Base
  498. validates :name, presence: true
  499. validates :email, presence: true
  500. end
  501. ```
  502.  
  503. *長さを検証する*
  504.  
  505. 名前の長さにも制限を与える必要がある。51文字の名前は長すぎることを検証する。
  506.  
  507. また、255文字以上のメールアドレスについても制限を与える。
  508.  
  509. *nameの長さの検証に対するテスト*
  510.  
  511. ```
  512. RED
  513. test/models/user_test.rb
  514. require 'test_helper'
  515.  
  516. class UserTest < ActiveSupport::TestCase
  517.  
  518. def setup
  519. @user = User.new(name: "Example User", email: "user@example.com")
  520. end
  521. .
  522. .
  523. .
  524. test "name should not be too long" do
  525. @user.name = "a" * 51
  526. assert_not @user.valid?
  527. end
  528.  
  529. test "email should not be too long" do
  530. @user.email = "a" * 244 + "@example.com"
  531. assert_not @user.valid?
  532. end
  533. end
  534. ```
  535.  
  536. この時点でのテストは失敗する。
  537.  
  538. これをパスさせるためには、長さを強制するバリデーションを指定する必要がある。
  539.  
  540. *name属性に長さの検証を追加する*
  541.  
  542. ```
  543. GREEN
  544. app/models/user.rb
  545. class User < ActiveRecord::Base
  546. validates :name, presence: true, length: { maximum: 50 }
  547. validates :email, presence: true, length: { maximum: 255 }
  548. end
  549. ```
  550.  
  551.  
  552.  
  553. ### 理解できなかったもの
  554.  
  555.  
  556.  
  557.  
  558. ### 調べたもの
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement