概要
第2段階の仕様のうちプロフィールに続いて記事投稿の機能を実装していく。
まず、記事投稿に必要なモデルとデータベースのテーブルを準備する。
- Post:投稿記事のモデル
- PostImage:投稿記事に付加可能な画像ファイルのモデル
手順の詳細は「モデル生成とマイグレーション」、「アソシエーション~基本」を参照
モデルの生成
Postモデル
以下のRailsコマンドでPost
モデルを生成する。User
モデルを参照するため、user:references
を指定。
1 |
$ rails generate model post user:references message:text |
生成されたモデルの内容を確認。references
指定に基づいて、Railsによりbelongs_to
が記述されている。
app/models/post.rb
1 2 3 |
class Post < ApplicationRecord belongs_to :user end |
モデルと同時に生成されるマイグレーションファイルを確認。ここでもusers
テーブルを参照する外部キーが設定されている。
20210331121751_create_posts
1 2 3 4 5 6 7 8 9 10 |
class CreatePosts < ActiveRecord::Migration[5.1] def change create_table :posts do |t| t.references :user, foreign_key: true t.text :message t.timestamps end end end |
PostImageモデル
以下のRailsコマンドでPost
モデルを生成する。Post
モデルを参照するため、post:references
を指定。
1 |
$ rails generate model post_image post:references file_name:string |
生成されたモデルの内容を確認。references
指定に基づいて、Railsによりbelongs_to
が記述されている。
models/post_image.rb
1 2 3 |
class PostImage < ApplicationRecord belongs_to :post end |
モデルと同時に生成されるマイグレーションファイルを確認。ここでもposts
テーブルを参照する外部キーが設定されている。
20210331122545_create_post_images.rb
1 2 3 4 5 6 7 8 9 10 |
class CreatePostImages < ActiveRecord::Migration[5.1] def change create_table :post_images do |t| t.references :post, foreign_key: true t.string :file_name t.timestamps end end end |
アソシエーションの設定
User
は複数の記事(Post
)を投稿するため、Userモデルにhas_many
を追加する。
models/User.rb
1 2 3 4 5 6 |
class User < ApplicationRecord has_many :posts ..... end |
1つの記事(Post
)が複数の画像(PostImage
)を持つことができるので、Post
モデルにhas_many
を設定する。post_images
と複数形になっている点に注意。
さらに、記事投稿時に画像ファイルも削除するよう、dependent
も設定。
models/post.rb
1 2 3 4 5 |
class Post < ApplicationRecord belongs_to :user # Railsにより記述済み # Postは複数のPostImageを持ち、消去時にPostImageも併せて消去 has_many :post_images, dependent: :destroy end |
post_image.rb
はPost
に従属するが、Railsによってbelongs_to
が設定済みなので編集不要。
マイグレート
以上の設定に基づいてマイグレーションを実行。その結果、posts
テーブルとpost_images
テーブルが生成される。
1 2 3 4 5 6 7 8 9 10 11 |
mysql> show tables; +------------------------------+ | Tables_in_ex_bbs_development | +------------------------------+ | ar_internal_metadata | | post_images | | posts | | schema_migrations | | users | +------------------------------+ 5 rows in set (0.00 sec) |
posts
テーブル、post_images
テーブルの構造を確認。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
mysql> DESCRIBE posts; +------------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | user_id | bigint(20) | YES | MUL | NULL | | | message | text | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec) mysql> DESCRIBE post_images; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | post_id | bigint(20) | YES | MUL | NULL | | | file_name | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec) |
rails consoleでの確認
rails console
でアソシエーションが機能しているか確認。
まず、User
に属するPost
データとPost
に属するPostImage
データを作成。
1 2 3 |
irb(main):001:0> user = User.find(1) irb(main):002:0> post = user.posts.create(message: "初投稿") irb(main):003:0> post.post_images(file_name: "dummy") |
テーブルに登録されたデータを確認。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> SELECT id, user_id, message FROM posts; +----+---------+-----------+ | id | user_id | message | +----+---------+-----------+ | 1 | 1 | 初投稿 | +----+---------+-----------+ 1 row in set (0.00 sec) mysql> SELECT id, post_id, file_name FROM post_images; +----+---------+-----------+ | id | post_id | file_name | +----+---------+-----------+ | 1 | 1 | dummy | +----+---------+-----------+ 1 row in set (0.00 sec) |
このあとpost.destroyにより、postデータとPostImageデータが連動して削除される。