rails7: 各种 tag/taggable/tagging 多态关联

实际项目中的各种 tag
更新于: 2023-12-09 22:46:17
表结构

我的需求

  • 我有 posts 文章表
  • 我有 albums 相册表
  • 我现在有个 tag 标签的功能,我希望与这2个表之间多对多关系
  • 另外: 用 rails 的多态关联实现功能

创建 models

# 之前已经创建
rails g model Post
rails g model Work title:string:index:uniq content:text

# 最关键的就是这张表了
rails g model Tag name:string
rails g model Tagging taggable:references{polymorphic} tag:references

代码参考

Model代码
models/tag.rb
class Tag < ApplicationRecord
  has_many :taggings, dependent: :destroy
  has_many :posts, through: :taggings, source: :taggable, source_type: 'post'
  has_many :works, through: :taggings, source: :taggable, source_type: 'work'
end
models/tagging.rb
class Tagging < ApplicationRecord
  belongs_to :taggable, polymorphic: true
  belongs_to :tag
end
models/post.rb
class Post < ApplicationRecord
  # ... 省略10000行代码

  has_many :taggings, as: :taggable, dependent: :destroy
  has_many :tags, through: :taggings
end
models/work.rb
class Work < ApplicationRecord

  has_many :taggings, as: :taggable, dependent: :destroy
  has_many :tags, through: :taggings
end

业务 model

抽象出一个 app/models/concerns/taggable.rb

# app/models/concerns/taggable.rb
module Taggable
  extend ActiveSupport::Concern

  included do
    has_many :taggings, as: :taggable, dependent: :destroy
    has_many :tags, through: :taggings
  end
end

优化后的 model

# app/models/post.rb
class Post < ApplicationRecord
  include Taggable
end

# app/models/work.rb
class Work < ApplicationRecord
  include Taggable
end

关于 dependent

dependent: :destroy: 这是一个选项,表示当拥有这个关联的对象(比如 Post 或 Work)被销毁时
关联的 Tagging 对象也应该被销毁。换句话说,当你删除一个文章或相册时,与之相关的标签关联信息将被删除,以防止悬空的标签关系。

路由

重点是设置这里 defaults: { format: :json }

Rails.application.routes.draw do
  root "pages#welcome"
  # default response format is JSON
  resources :tags, only: [:index, :show], defaults: { format: :json }
  get "up" => "rails/health#show", as: :rails_health_check
end

参考