😄
超小ネタ ポリモーフィック関連はモデルインスタンスを使って検索できる
Railsのポリモーフィック関連ではモデルインスタンスをwhereメソッドの検索条件として設定できることを知ったので超小ネタとして残しておきます。
テーブル・モデル定義
例として、comments
テーブルを commentable
ポリモーフィック関連で posts
と articles
モデルに関連付ける場合を示します。
まず、ridgepoleのSchemafileでテーブルを作成する手順です。
※ridgepole使ってない方ごめんなさい...
# Schemafile
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps
end
create_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
create_table :comments do |t|
t.text :content
t.references :commentable, polymorphic: true, index: true
t.timestamps
end
db/schema.rbはコチラ
# db/schema.rb
ActiveRecord::Schema[7.1].define(version: 0) do
create_table "posts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "articles", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.text "content"
t.bigint "commentable_id"
t.string "commentable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable_type_and_commentable_id"
end
end
次に、モデルの設定を行います:
# app/models/post.rb
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
# app/models/article.rb
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
これで、Post
モデルと Article
モデルはそれぞれ Comment
モデルとポリモーフィックに関連付けられ、1つの comments
テーブルで管理されます。
動作確認
irb(main):001> Post.new().save
TRANSACTION (0.2ms) BEGIN
Post Create (0.9ms) INSERT INTO `posts` (`title`, `content`, `created_at`, `updated_at`) VALUES (NULL, NULL, '2024-06-27 09:15:12.076130', '2024-06-27 09:15:12.076130')
TRANSACTION (1.4ms) COMMIT
=> true
Postを作成。
irb(main):003> Comment.new(commentable: post).save
TRANSACTION (0.3ms) BEGIN
Comment Create (1.0ms) INSERT INTO `comments` (`content`, `commentable_id`, `commentable_type`, `created_at`, `updated_at`) VALUES (NULL, 1, 'Post', '2024-06-27 09:15:42.899920', '2024-06-27 09:15:42.899920')
TRANSACTION (5.3ms) COMMIT
=> true
CommentにPostを紐づけて作成。
irb(main):005> post = Post.first
Post Load (0.9ms) SELECT `posts`.* FROM `posts` ORDER BY `posts`.`id` ASC LIMIT 1
=>
#<Post:0x0000ffff62298e90
...
irb(main):006> Comment.where(commentable: post)
Comment Load (2.7ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`commentable_type` = 'Post' AND `comments`.`commentable_id` = 1 /* loading for pp */ LIMIT 11
=>
[#<Comment:0x0000ffff6229dfd0
id: 1,
content: nil,
commentable_id: 1,
commentable_type: "Post",
created_at: Thu, 27 Jun 2024 09:15:42.899920000 UTC +00:00,
updated_at: Thu, 27 Jun 2024 09:15:42.899920000 UTC +00:00>]
Commentを検索するときに、commentableにPostインスタンスを設定してあげると
WHERE comments.commentable_type = 'Post'
という検索条件が入っているのが分かる。
Discussion