用户应该可以固定帖子/创建粘贴帖子。但他应该只被允许只针一个帖子。因此,如果他决定创建一个新的固定帖子/别针另一个帖子,他必须“取消固定”旧帖子(并显示错误信息)。
我的用户和帖子模型之间有一个简单的关联,post模型有一个名为“pinned”的列,它是一个布尔值(true或false)。这就是我尝试过的:
模型/ user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
validates_uniqueness_of :posts, if: :only_one_pinned_post
def only_one_pinned_post
if self.post.where(pinned: true).size == 1
true
else
false
end
end
end
模型/ post.rb
class Post < ApplicationRecord
belongs_to :user
end
我的问题:
答案 0 :(得分:1)
由于您希望确保仅在固定帖子上,您可能希望将验证添加到Post
模型中:
class Post < ActiveRecord::Base
belongs_to :user
scope :pinned, -> { where(pinned:true) }
scope :without, ->(id) { where.not(id: id) if id }
validate :only_one_pinned_post_per_user
private
def only_one_pinned_post_per_user
if pinned? && user.posts.pinned.without(id).any?
errors.add(:pinned, 'Another post ist already pinned')
end
end
end
我想知道(从可用性的角度来看)以不同的方式实现它是否更好:也许你不应该告诉用户他不能固定多个帖子。相反,您可以保存新固定的帖子并自动取消固定任何其他帖子。这可以通过后保存回调来完成:
class Post < ActiveRecord::Base
belongs_to :user
scope :pinned, -> { where(pinned:true) }
scope :without, ->(id) { where.not(id: id) if id }
after_save :ensure_only_one_pinned_post
private
def ensure_only_one_pinned_post
user.posts.pinned.without(id).update_all(pinned: false) if pinned?
end
end
without
范围用于查找并且不计算具有给定id
的帖子。我在这种情况下使用它来确保在查找其他已经固定的帖子时找不到当前创建或更新的帖子。
答案 1 :(得分:1)
这是对你的问题的另一种看法(简单而干净):
class User < ApplicationRecord
has_many :posts
# Helper to get only one pinned post
has_one :pinned_post, -> { where(pinned: true) }, class_name: "Post"
end
class Post < ApplicationRecord
belongs_to :user
after_save do
if pinned?
# Automatically unpin any other pinned posts
user.posts.where("id != ?", id).update_all(pinned: false)
end
end
end
答案 2 :(得分:0)
我没有测试过,但我认为这应该是合适的。基本上,方法only_one_pinned_post
在验证期间执行,并且在用户已经有固定帖子的情况下,向错误对象添加消息,这将阻止对象被保存。
class User < ApplicationRecord
scope :pinned, -> { where(pinned: true) }
has_many :posts, dependent: :destroy
validate :only_one_pinned_post
def only_one_pinned_post
if pinned && (posts.pinned.pluck(:id) - [id]).any?
errors.add(:pinned, 'Only one pinned post')
end
end
end
条件中的表达式posts.pinned.pluck(:id) - [id]
返回固定帖子的ID列表,不包括我们要保存的帖子。这样我们就可以修改该用户的现有固定帖子。
答案 3 :(得分:0)
在(user_id, pinned)
复合字段的数据库中创建唯一索引。这是确定用户没有多个固定帖子的唯一途径。所有其他应用程序级别的验证都不可靠(尽管您可能/应该使用另外到唯一索引)