Ruby
Rails
RubyOnRails
Railsチュートリアル

Ruby on Rails チュートリアル 5.0(第4版)6.1演習

Ruby on Rails チュートリアル 5.0(第4版)を学習中です。
演習問題を自分なりに実施しました。
もし間違い等あればコメントいただけると嬉しいです。

演習6.1.1.1

<問題>
Railsはdb/ディレクトリの中にあるschema.rbというファイルを使っています。これはデータベースの構造 (スキーマ (schema) と呼びます) を追跡するために使われます。さて、あなたの環境にあるdb/schema.rbの内容を調べ、その内容とマイグレーションファイル (リスト 6.2) の内容を比べてみてください。

<解答>

schema.rb
ActiveRecord::Schema.define(version: 20170203234505) do

  create_table "users", force: :cascade do |t|
    t.string   "name"
    t.string   "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end
20170203234505_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

異なる点は以下の2つ。

①「created_at,updated_at」と「t.timestamps」
⇒本文中に「t.timestampsは特別なコマンドで、created_atとupdated_atという2つの「マジックカラム (Magic Columns)」を作成します。」とあるので、実質構成は同じ。

②「create_table」に対して「force: :cascade」の有無
⇒「force: :cascade」:外部キーが適切であればスキーマが再読み込みできるようになります。(参照元:https://railsguides.jp/4_2_release_notes.html)

ないとどうなるのかは現時点ではわからない。。。

演習6.1.1.2

<問題>
ほぼすべてのマイグレーションは、元に戻すことが可能です (少なくとも本チュートリアルにおいてはすべてのマイグレーションを元に戻すことができます)。元に戻すことを「ロールバック (rollback)と呼び、Railsではdb:rollbackというコマンドで実現できます。
$ rails db:rollback
上のコマンドを実行後、db/schema.rbの内容を調べてみて、ロールバックが成功したかどうか確認してみてください (コラム 3.1ではマイグレーションに関する他のテクニックもまとめているので、参考にしてみてください)。 上のコマンドでは、データベースからusersテーブルを削除するためにdrop_tableコマンドを内部で呼び出しています。 これがうまくいくのは、drop_tableとcreate_tableがそれぞれ対応していることをchangeメソッドが知っているからです。この対応関係を知っているため、ロールバック用の逆方向のマイグレーションを簡単に実現することができるのです。なお、あるカラムを削除するような不可逆なマイグレーションの場合は、changeメソッドの代わりに、upとdownのメソッドを別々に定義する必要があります。 詳細については、Railsガイドの「Active Record マイグレーション」を参照してください。

<解答>
指示通り以下を実行
$ rails db:rollback

schema.rb
ActiveRecord::Schema.define(version: 0) do

end

ロールバック完了。

演習6.1.1.3

<問題>
もう一度rails db:migrateコマンドを実行し、db/schema.rbの内容が元に戻ったことを確認してください。

<解答>
6.1.1.1そのままなので省略。

演習6.1.2.1

<問題>
Railsコンソールを開き、User.newでUserクラスのオブジェクトが生成されること、そしてそのオブジェクトがApplicationRecordを継承していることを確認してみてください (ヒント: 4.4.4で紹介したテクニックを使ってみてください)。

<解答>

>> User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
>> User.superclass
=> ApplicationRecord(abstract)

演習6.1.2.2

<問題>
同様にして、ApplicationRecordがActiveRecord::Baseを継承していることについて確認してみてください。

<解答>

>> ApplicationRecord.superclass
=> ActiveRecord::Base

演習6.1.3.1

<問題>
user.nameとuser.emailが、どちらもStringクラスのインスタンスであることを確認してみてください。

<解答>

>> user.name.class
=> String

>> user.email.class
=> String

演習6.1.3.2

<問題>
created_atとupdated_atは、どのクラスのインスタンスでしょうか?

<解答>

>> user.created_at.class
=> ActiveSupport::TimeWithZone

>> user.updated_at.class
=> ActiveSupport::TimeWithZone

演習6.1.4.1

<問題>
nameを使ってユーザーオブジェクトを検索してみてください。また、 find_by_nameメソッドが使えることも確認してみてください (古いRailsアプリケーションでは、古いタイプのfind_byをよく見かけることでしょう)。

<解答>

>> User.find_by(name: "Michael Hartl")
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Michael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2017-02-04 05:46:02", updated_at: "2017-02-04 05:46:02">

>> User.find_by_name("Michael Hartl")                                                                            
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Michael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2017-02-04 05:46:02", updated_at: "2017-02-04 05:46:02">

演習6.1.4.2

<問題>
実用的な目的のため、User.allはまるで配列のように扱うことができますが、実際には配列ではありません。 User.allで生成されるオブジェクトを調べ、ArrayクラスではなくUser::ActiveRecord_Relationクラスであることを確認してみてください。

<解答>

>> User.all.class
=> User::ActiveRecord_Relation

演習6.1.4.3

<問題>
User.allに対してlengthメソッドを呼び出すと、その長さを求められることを確認してみてください (4.2.3)。

<解答>

>> User.all.length
  User Load (0.3ms)  SELECT "users".* FROM "users"
=> 2

演習6.1.5.1

<問題>
userオブジェクトへの代入を使ってname属性を使って更新し、saveで保存してみてください。

<解答>

>> user.name="Taro Yamada"
=> "Taro Yamada"
>> user.save
   (0.2ms)  SAVEPOINT active_record_1
  SQL (1.1ms)  UPDATE "users" SET "updated_at" = ?, "name" = ? WHERE "users"."id" = ?  [["updated_at", 2017-02-04 06:34:26 UTC], ["name", "Taro Yamada"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

演習6.1.5.2

<問題>
今度はupdate_attributes(*)を使って、email属性を更新および保存してみてください。

<解答>

>> user.update_attribute(:email,"yamada@mail.com")
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.1ms)  UPDATE "users" SET "email" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["email", "yamada@mail.com"], ["updated_at", 2017-02-04 06:37:31 UTC], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

>> user.email
=> "yamada@mail.com"

*問題では「update_attributes」となっていますが、最後の「s」は不要です。

演習6.1.5.3

<問題>
同様にして、マジックカラムであるcreated_atも直接更新できることを確認してみてください。ヒント: 更新するときは「1.year.ago」を使うと便利です。これはRails流の時間指定の1つで、現在の時刻から1年前の時間を算出してくれます。

<解答>

>> user.update_attribute(:created_at,1.year.ago)
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.2ms)  UPDATE "users" SET "created_at" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["created_at", 2016-02-04 06:43:54 UTC], ["updated_at", 2017-02-04 06:42:00 UTC], ["id", 1]]
   (0.0ms)  RELEASE SAVEPOINT active_record_1
=> true

>> user.created_at
=> Thu, 04 Feb 2016 06:43:54 UTC +00:00

関連記事

Ruby on Rails チュートリアル 完全攻略 概要と演習解答総まとめ
http://mochikichi.hatenablog.com/entry/rails_tutorial_guide