[じぶん用メモ] RailsでPry・DBと仲良くなろう


###はじめに
RailsでPryを使ってDBの操作をする時に
必要なコマンドや考え方を自分用メモとして残します。


###環境
MacOS Mojave
Ruby 2.6.4
Rails 6.0.3.3
Vue 2.6.12
Webpack 4.44.2
yarn 1.22.5
Docker 2.3.0.5
VScode

####環境構築
Dockerを用いたVue Rails6環境構築については以下にまとめています。
[リンク：Rails6 Vueの連動方法(環境構築から)](https://qiita.com/x5dwimpejx/items/3389952db62f27c4aa0d)

###モデルとDBのマイグレーション関連

####Dockerコンテナは上げておきます。

```rb:
Docker-compose up
```

####Articleモデルの作成

```rb:
Docker-compose exec web rails g model Article name:string content:text

Running via Spring preloader in process 207
      invoke  active_record
      create    db/migrate/20200926174356_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml
```

####Commentモデルの作成

```rb:
Docker-compose exec web rails g model Comment comment:text

Running via Spring preloader in process 276
      invoke  active_record
      create    db/migrate/20200926174846_create_comments.rb
      create    app/models/comment.rb
      invoke    test_unit
      create      test/models/comment_test.rb
      create      test/fixtures/comments.yml
```

####DBへの反映

```rb:
Docker-compose exec web rails db:migrate

== 20200926174356 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0505s
== 20200926174356 CreateArticles: migrated (0.0519s) ==========================

== 20200926174846 CreateComments: migrating ===================================
-- create_table(:comments)
   -> 0.0296s
== 20200926174846 CreateComments: migrated (0.0310s) ==========================
```

####DBのステータス確認

```rb:
Docker-compose exec web rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200926174356  Create articles
   up     20200926174846  Create comments
```

####DBのバージョン

```rb:
Docker_Rails6_Vue hiroki$ Docker-compose exec web rails db:version
Current version: 20200926174846
```

####Schema.rbでもバージョン確認
```rb:schema.rb
ActiveRecord::Schema.define(version: 2020_09_26_174846) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "articles", force: :cascade do |t|
    t.string "name"
    t.text "content"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "comments", force: :cascade do |t|
    t.text "comment"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

end
```

####DBのロールバック

Docker-compose exec web rails db:rollback STEP=2とすると[+1]downされる。

つまり
Docker-compose exec web rails db:rollback STEP=1
と
Docker-compose exec web rails db:rollback
は同じ

```rb:
Docker-compose exec web rails db:rollback

== 20200926174846 CreateComments: reverting ===================================
-- drop_table(:comments)
   -> 0.0104s
== 20200926174846 CreateComments: reverted (0.0156s) ==========================
```

####DBのステータス確認

マイグレーションファイルの削除やDBのカラムの追加などはdown時に実施する必要がある。
一般的にDBのてカラムの追加は別にマイグレーションファイルを作成して記述する。

```rb:
Docker-compose exec web rails db:migrate:status

database: myapp_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200926174356  Create articles
  down    20200926174846  Create comments
```

Docker-compose exec web rails db:migrateをして戻しておきます。


###Pryの起動

####Pryを起動する

```rb:
Docker-compose exec web rails c

Running via Spring preloader in process 1191
Loading development environment (Rails 6.0.3.3)
[1] pry(main)> 
```

####articleオブジェクトを新規作成

```rb:
pry(main)> @article = Article.new
=> #<Article:0x0000555d5c5340a8 id: nil, name: nil, content: nil, created_at: nil, updated_at: nil>
pry(main)> 
```

####articleオブジェクトに値を入れる

```rb:
pry(main)> @article.name = "記事1"
=> "記事1"

pry(main)> @article.content = "記事の内容です"
=> "記事の内容です"
```

####articleオブジェクトがバリデーションに合格するか

```rb:
pry(main)> @article.valid?
=> true
```

####articleオブジェクトをDBに保存する。

```rb:
pry(main)> @article.save!
   (0.5ms)  BEGIN
  Article Create (8.5ms)  INSERT INTO "articles" ("name", "content", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "記事1"], ["content", "記事の内容です"], ["created_at", "2020-09-26 18:18:00.150412"], ["updated_at", "2020-09-26 18:18:00.150412"]]
   (4.1ms)  COMMIT
=> true
```

####postgresに接続する。

```rb:
docker-compose exec db psql -U postgres -d myapp_development

psql (12.4 (Debian 12.4-1.pgdg100+1))
Type "help" for help.

myapp_development=# 
```

####データベースのリストを表示

```rb:
myapp_development=# \l
                                     List of databases
       Name        |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-------------------+----------+----------+------------+------------+-----------------------
 myapp_development | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 myapp_test        | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres          | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0         | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
                   |          |          |            |            | postgres=CTc/postgres
 template1         | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
                   |          |          |            |            | postgres=CTc/postgres
(5 rows)
```


####接続したDBのテーブルを表示
```rb:
myapp_development=# \d
                  List of relations
 Schema |         Name         |   Type   |  Owner   
--------+----------------------+----------+----------
 public | ar_internal_metadata | table    | postgres
 public | articles             | table    | postgres
 public | articles_id_seq      | sequence | postgres
 public | comments             | table    | postgres
 public | comments_id_seq      | sequence | postgres
 public | schema_migrations    | table    | postgres
(6 rows)
```

####テーブルのカラムを表示
```rb:
myapp_development=# \d articles
                                          Table "public.articles"
   Column   |              Type              | Collation | Nullable |               Default                
------------+--------------------------------+-----------+----------+--------------------------------------
 id         | bigint                         |           | not null | nextval('articles_id_seq'::regclass)
 name       | character varying              |           |          | 
 content    | text                           |           |          | 
 created_at | timestamp(6) without time zone |           | not null | 
 updated_at | timestamp(6) without time zone |           | not null | 
Indexes:
    "articles_pkey" PRIMARY KEY, btree (id)
```

####テーブルのカラムのデータを表示

```rb:
myapp_development=# select * from articles ;
 id | name  |    content     |         created_at         |         updated_at         
----+-------+----------------+----------------------------+----------------------------
  1 | 記事1 | 記事の内容です | 2020-09-26 18:18:00.150412 | 2020-09-26 18:18:00.150412
(1 row)
```
Pryで作成したデータが入っていますね。

###モデルの関連付け
Articleを親、Commentを子として関連づける

####article.rbを以下に書き換え


```rb:
class Article < ApplicationRecord
    has_many :comments
end
```

####comment.rbを以下に書き換え

```rb:
class Comment < ApplicationRecord
    belongs_to :article
end
```

####関連付けのマイグレーションファイルを追加

```rb:
docker-compose run web rails g migration Add_Article_Id_To_Comment

Running via Spring preloader in process 68
      invoke  active_record
      create    db/migrate/20200926184159_add_article_id_to_comment.rb
```


####作成されたマイグレーションファイルを以下に修正
単数形複数形、テーブルの位置を注意する。

```rb:
class AddArticleIdToComment < ActiveRecord::Migration[6.0]
  def change
    add_reference :comments, :article, foreign_key: true
  end
end
```

####postgresに接続する。

```rb:
docker-compose exec db psql -U postgres -d myapp_development

psql (12.4 (Debian 12.4-1.pgdg100+1))
Type "help" for help.

myapp_development=# 


```

####commentsテーブルにarticles_idが追加されていることを確認する。

```rb:
myapp_development=# \d comments  
                                          Table "public.comments"
   Column    |              Type              | Collation | Nullable |               Default                
-------------+--------------------------------+-----------+----------+--------------------------------------
 id          | bigint                         |           | not null | nextval('comments_id_seq'::regclass)
 comment     | text                           |           |          | 
 created_at  | timestamp(6) without time zone |           | not null | 
 updated_at  | timestamp(6) without time zone |           | not null | 
 article_id  | bigint                         |           |          | 
Indexes:
    "comments_pkey" PRIMARY KEY, btree (id)
    "index_comments_on_articles_id" btree (articles_id)
Foreign-key constraints:
    "fk_rails_d8ed532d4e" FOREIGN KEY (articles_id) REFERENCES articles(id)
```

####pryを起動する。

```rb:
comment = Comment.new
=> #<Comment:0x00007f1d8c4f2490 id: nil, comment: nil, created_at: nil, updated_at: nil, article_id: nil>
```

####commentsモデルにデータを格納する。

```rb:
comment.comment = "This is Comment"
=> "This is Comment"

comment.articles_id = 1
=> 1
```

####モデルで作成したインスタンスをDBに格納できるかバリデーションを行う。
```rb:
comment.valid?
=> true
```

####インスタンスをデータベースに保存する。

```rb:
comment.save
   (0.6ms)  BEGIN
  Comment Create (17.2ms)  INSERT INTO "comments" ("comment", "created_at", "updated_at", "article_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["comment", "This is Comment"], ["created_at", "2020-10-02 12:50:20.046429"], ["updated_at", "2020-10-02 12:50:20.046429"], ["article_id", 1]]
   (3.3ms)  COMMIT
=> true
```
####ID１のArticleインスタンスを作成する。
```rb:
article = Article.find(1)
  Article Load (3.6ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
=> #<Article:0x00007f1f0c612a38
 id: 1,
 name: "記事1",
 content: "記事の内容です",
 created_at: Sat, 26 Sep 2020 18:18:00 UTC +00:00,
 updated_at: Sat, 26 Sep 2020 18:18:00 UTC +00:00>
```

####ID1のArticleインスタンスに関連しているCommentsのデータを取得する。
```rb:
commnet = article.comments
=>   Comment Load (2.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."article_id" = $1  [["article_id", 1]]
[#<Comment:0x00007f1f0c81a088
  id: 1,
  comment: "This is Comment",
  created_at: Fri, 02 Oct 2020 12:50:20 UTC +00:00,
  updated_at: Fri, 02 Oct 2020 12:50:20 UTC +00:00,
  article_id: 1>]
```
####もう一つCommentインスタンスを作成する。
```rb:
commnet = Comment.new
=> #<Comment:0x00007f1f0ca3c780 id: nil, comment: nil, created_at: nil, updated_at: nil, article_id: nil>
```

####バリデーションを行う。
```rb:
commnet.valid?
=> false
```

####バリデーションエラー時のエラーを取得する。
```rb:
commnet.errors
=> #<ActiveModel::Errors:0x00007f1f0caa9d58
 @base=#<Comment:0x00007f1f0ca3c780 id: nil, comment: nil, created_at: nil, updated_at: nil, article_id: nil>,
 @details={:article=>[{:error=>:blank}]},
 @messages={:article=>["must exist"]}>
```

以上でD