使用嵌套has_many进行 Rails 唯一性验证



我正在建立一个民意调查网站,我想实现用户(IP地址(每次民意调查可以投票一次。我有以下型号:

class Poll < ApplicationRecord
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, allow_destroy: true
end
class Answer < ApplicationRecord
belongs_to :poll
has_many :votes
end
class Vote < ApplicationRecord
validates_uniqueness_of :ip_address
belongs_to :answer
end

使用我当前的解决方案,用户可以在一个民意调查中投票一次,然后他不能在另一个民意调查中投票。 我应该使用什么来validates_uniqueness_of :ip_address每个投票? 我试图通过民意调查使用范围,但它不起作用。

PS:我知道IP地址不是验证唯一投票的最佳解决方案。

您需要作用域的唯一性

validates :ip_address, uniqueness: { scope: :answer_id }

它不允许每个answer重复ip_address

https://guides.rubyonrails.org/active_record_validations.html#uniqueness

您也可以通过将其添加到迁移中来在数据库级别强制执行它,尽管这是可选的

add_index :votes, [:ip_address, :answer_id], unique: true

但上述解决方案只会防止用户多次不投票支持答案。如果你想poll唯一性,一种选择是将poll_id也保存在answers表中,然后定义唯一性,

或者,第二个选项是在模型中定义自定义验证Vote

validate :uniqueness_with_poll
def uniqueness_with_poll
errors.add(:answer_id, 'already voted for poll') if answer_for_poll_exists?
end
def answer_for_poll_exists?
answer_voted = Vote.where(ip_address: ip_address).pluck(:answer_id)
return false if answer_voted.blank?
answer.poll.answers.where(id: answer_voted).exists?
end

然后定义一个answer_for_poll_exists?方法来检查民意调查是否已投票,但这可能会很昂贵。

希望对您有所帮助!

最新更新