👌
Associationを試す...!(1:多)
リレーションはよく使うよね。
けど、理解が曖昧な感じがするので数打って理解する
一つ目の User Model を作成する
- User Model を作成する
rails g model User name:string email:string
invoke active_record
create db/migrate/20220227085625_create_users.rb
create app/models/user.rb
rails db:migrate
と、こうなる。
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
| created_at | datetime(6) | NO | | NULL | |
| updated_at | datetime(6) | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
- お試しにデータ登録
[1] pry(main)> user = User.new(name: "nyasu", email: "nyasu@example.com")
=> #<User:0x000000010a1661f0 id: nil, name: "nyasu", email: "nyasu@example.com", created_at: nil, updated_at: nil>
[2] pry(main)> user.save
TRANSACTION (4.9ms) BEGIN
User Create (5.0ms) INSERT INTO `users` (`name`, `email`, `created_at`, `updated_at`) VALUES ('nyasu', 'nyasu@example.com', '2022-03-21 10:46:53.028514', '2022-03-21 10:46:53.028514')
TRANSACTION (23.4ms) COMMIT
=> true
関連付けて post を作成する
rails g model post content:text user:references
invoke active_record
create db/migrate/20220321094237_create_posts.rb
create app/models/post.rb
rails db:migrate
と、こうなる
mysql> desc posts;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| content | text | YES | | NULL | |
| user_id | bigint(20) | NO | MUL | NULL | |
| created_at | datetime(6) | NO | | NULL | |
| updated_at | datetime(6) | NO | | NULL | |
+------------+-------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
- 関連付けを利用して .build で登録する
[1] pry(main)> user.post.build(content: "nyas comment")
=> #<Post:0x000000010a1debf0 id: nil, content: "nyas comment", user_id: 2, created_at: nil, updated_at: nil>
[2] pry(main)> user.post.build(content: "nyas comment2")
=> #<Post:0x000000010a2e6340 id: nil, content: "nyas comment2", user_id: 2, created_at: nil, updated_at: nil>
[3] pry(main)> user.post.build(content: "nyas comment3")
=> #<Post:0x000000010a32e758 id: nil, content: "nyas comment3", user_id: 2, created_at: nil, updated_at: nil>
- nyasu user の post 一覧を取得する
[4] pry(main)> user.posts
=> [#<Post:0x000000010a1debf0 id: nil, content: "nyas comment", user_id: 2, created_at: nil, updated_at: nil>,
#<Post:0x000000010a2e6340 id: nil, content: "nyas comment2", user_id: 2, created_at: nil, updated_at: nil>,
#<Post:0x000000010a32e758 id: nil, content: "nyas comment3", user_id: 2, created_at: nil, updated_at: nil>]
- 上記の状態で rails c を再度立ち上げなおすと登録した post データが存在しない...!
- これは、 .build が Model.new に該当する為なので、別途保存しておかないとダメ。
[1] pry(main)> user = User.find_by(name: "nyasu")
User Load (4.5ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'nyasu' LIMIT 1
=> #<User:0x0000000114ac9198 id: 2, name: "nyasu", email: "nyasu@example.com", created_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00>
[2] pry(main)> user.posts
Post Load (7.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 2
=> []
- あらためて .create で登録する
- 今度は同時に SQL query も発行され、Commitまで完了しているのでデータも登録されているのがログからもわかる。
[5] pry(main)> user.post.create(content: "nyasu comment")
TRANSACTION (4.2ms) BEGIN
Post Create (5.1ms) INSERT INTO `posts` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('nyasu comment', 2, '2022-03-21 10:54:27.497592', '2022-03-21 10:54:27.497592')
TRANSACTION (19.9ms) COMMIT
=> #<Post:0x0000000114c80298 id: 2, content: "nyasu comment", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00>
[6] pry(main)> user.post.create(content: "nyasu comment2")
TRANSACTION (3.5ms) BEGIN
Post Create (4.7ms) INSERT INTO `posts` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('nyasu comment2', 2, '2022-03-21 10:54:31.490075', '2022-03-21 10:54:31.490075')
TRANSACTION (6.3ms) COMMIT
=> #<Post:0x0000000114ea41c8 id: 3, content: "nyasu comment2", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00>
[7] pry(main)> user.post.create(content: "nyasu comment3")
TRANSACTION (4.5ms) BEGIN
Post Create (5.2ms) INSERT INTO `posts` (`content`, `user_id`, `created_at`, `updated_at`) VALUES ('nyasu comment3', 2, '2022-03-21 10:54:33.077482', '2022-03-21 10:54:33.077482')
TRANSACTION (8.6ms) COMMIT
=> #<Post:0x0000000114effeb0 id: 4, content: "nyasu comment3", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00>
[8] pry(main)>
% rails c
Loading development environment (Rails 7.0.2.2)
[1] pry(main)> user = User.find_by(name: "nyasu")
User Load (3.1ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'nyasu' LIMIT 1
=> #<User:0x000000010a4894b8 id: 2, name: "nyasu", email: "nyasu@example.com", created_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00>
[2] pry(main)> user.posts
Post Load (3.6ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 2
=> [#<Post:0x000000010a8308a0 id: 2, content: "nyasu comment", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00>,
#<Post:0x000000010a920ad0 id: 3, content: "nyasu comment2", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00>,
#<Post:0x000000010a9208f0 id: 4, content: "nyasu comment3", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00>]
[3] pry(main)>
- posts table を確認してもわかる。
mysql> select * from posts;
+----+----------------+---------+----------------------------+----------------------------+
| id | content | user_id | created_at | updated_at |
+----+----------------+---------+----------------------------+----------------------------+
| 1 | nyasu | 1 | 2022-03-21 10:10:18.669882 | 2022-03-21 10:10:18.669882 |
| 2 | nyasu comment | 2 | 2022-03-21 10:54:27.497592 | 2022-03-21 10:54:27.497592 |
| 3 | nyasu comment2 | 2 | 2022-03-21 10:54:31.490075 | 2022-03-21 10:54:31.490075 |
| 4 | nyasu comment3 | 2 | 2022-03-21 10:54:33.077482 | 2022-03-21 10:54:33.077482 |
+----+----------------+---------+----------------------------+----------------------------+
4 rows in set (0.01 sec)
結局リレーションってなんの為に...?
- 関連付けをしておく事で、rails での Model clust に関連付け用の method が新しく生えて、楽に、便利に検索したり、データを生成したり、検索の仕方(SQL queryの使い方)に統一感をもたらす事でindexであったり、DB cacheであったりが用意になったりする様子。
- また、削除する時にも関連データ 特定user を削除した時に、特定Userが登録したデータを合わせて削除するとかも楽になる。
- 結局プロダクトでどういった表示、データ作成、検索、使われ方がされるのか次第なのかな?と、思います。
- null 制約を付与する為に細かく table を分けたりする場合もあるようで、奥が深いなぁ。と思いました(小並)
手間をかけて投稿一覧を取得する
- user を探す
[1] pry(main)> user = User.find_by(name: "nyasu")
User Load (3.0ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'nyasu' LIMIT 1
=> #<User:0x0000000111f4ff58 id: 2, name: "nyasu", email: "nyasu@example.com", created_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00>
- その後、該当ユーザの post を探す
[2] pry(main)> post = Post.where(user_id: user)
Post Load (7.2ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 2
=> [#<Post:0x0000000112402f00 id: 2, content: "nyasu comment", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00>,
#<Post:0x0000000112402e38 id: 3, content: "nyasu comment2", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00>,
#<Post:0x0000000112402d70 id: 4, content: "nyasu comment3", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00>]
楽に投稿一覧を探す
[7] pry(main)> user = User.find_by(name: "nyasu")
User Load (4.9ms) SELECT `users`.* FROM `users` WHERE `users`.`name` = 'nyasu' LIMIT 1
=> #<User:0x0000000112492358 id: 2, name: "nyasu", email: "nyasu@example.com", created_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:46:53.028514000 UTC +00:00>
[8] pry(main)> user.posts
Post Load (3.7ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 2
=> [#<Post:0x0000000112569768 id: 2, content: "nyasu comment", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:27.497592000 UTC +00:00>,
#<Post:0x0000000112579078 id: 3, content: "nyasu comment2", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:31.490075000 UTC +00:00>,
#<Post:0x0000000112578e98 id: 4, content: "nyasu comment3", user_id: 2, created_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00, updated_at: Mon, 21 Mar 2022 10:54:33.077482000 UTC +00:00>]
[9] pry(main)>
備考
- 今回使った ER 図生成 ( Mac OS )
- 下記を実行すると、 DB 情報を読み取って erd.pdf が生成される。
brew install graphviz
group :development, :test do
gem 'rails-erd'
end
bundle exec erd
Discussion