刚开始使用带有Rails 4项目的STI。假设我有User
和Blog
,并且User
可以将其非公开博客与editors
或normal viewers
分享给其他用户。
将type
列放在users
表中对我来说没有意义,因为在项目中,用户不仅与blogs
相关联,还与事物相关联比如posts
。 (这里的博客更像是一个平台,帖子是文章。这里只是一个想法,可能是其他两件事。)
所以我使用另一个名为BlogUserAssociation
的模型来管理上述共享关系。基本上这个模型包含type
列,我从中继承了BlogEditorAssociation
和BlogViewerAssociation
。 (名称有点笨拙。)第一个问题,这是一种推荐的方式来处理"共享"情况?
根据上述想法,我有:
# blog.rb
class Blog < ActiveRecord::Base
...
has_many :blog_user_associations, dependent: :destroy
has_many :editors, through: :blog_editor_associations, source: :user
has_many :allowed_viewers, through: :blog_viewer_associations, source: :user # STI
...
和
# user.rb
class User < ActiveRecord::Base
...
has_many :blog_user_associations, dependent: :destroy
has_many :editable_blogs, through: :blog_editor_associations, source: :blog
has_many :blogs_shared_for_view, through: :blog_viewer_associations, source: :blog
...
但是当我尝试用Rspec测试时,
it { should have_many(:editors).through(:blog_editor_associations).source(:user) }
我收到错误undefined method 'klass' for nil:NilClass
我相信这是因为我在has_many blog_editor_associations
中没有说User
。但我认为blog_editor_associations
继承自blog_viewer_associations
,我不必再为子模型说has_many
。那么是否有理由不自动将has_many
绑定到子模型?
答案 0 :(得分:1)
BlogUser
,并添加布尔can_edit
列。值true
表示用户可以编辑关联的博客。
然后模型看起来像这样:
class Blog < ActiveRecord::Base
has_many :blog_users
has_many :users, through: :blog_users
scope :editable, -> { where(blog_users: {can_edit: true}) }
end
class BlogUser < ActiveRecord::Base
belongs_to :blog
belongs_to :user
end
class User < ActiveRecord::Base
has_many :blog_users
has_many :blogs, through: :blog_users
scope :editors, -> { where(blog_users: {can_edit: true}) }
end
因此user.blogs
检索与该用户关联的所有博客,user.blogs.editable
检索用户可以编辑的所有博客。 blog.users
检索与博客关联的所有用户,blog.users.editors
检索可以编辑博客的所有用户。
一些测试证明:
require 'rails_helper'
RSpec.describe User, type: :model do
describe "A user with no associated blogs" do
let(:user) { User.create! }
it "has no blogs" do
expect(user.blogs.empty?).to be true
expect(user.blogs.editable.empty?).to be true
end
end
describe "A user with a non-editable blog association" do
let(:user) { User.create! }
let(:blog) { Blog.create! }
before do
user.blogs << blog
end
it "has one blog" do
expect(user.blogs.count).to eq 1
end
it "has no editable blogs" do
expect(user.blogs.editable.empty?).to be true
end
end
describe "A user with an editable blog association" do
let(:user) { User.create! }
let(:blog) { Blog.create! }
before do
user.blog_users << BlogUser.new(blog: blog, user: user, can_edit: true)
end
it "has one blog" do
expect(user.blogs.count).to eq 1
end
it "has one editable blog" do
expect(user.blogs.editable.count).to eq 1
end
end
end