如何验证rails中的表单字段,使该值对该表单实例是唯一的,但在整个数据库中不是唯一的?
我有一张表格
有用户可以创建报价的rails。关于我是如何工作的更多细节
here
(模型、控制器、架构、表单)。
该表单允许用户共享一位艺术家(如DavidBowie)对另一位艺术家(如LouReed)的引用。因此,引用可能如下所示:
Topic: David Bowie
Content: "He was a master."
Speaker: Lou Reed
演讲者和主题都是来自我的艺术家模型的关联。模型如下所示:
class Quote < ApplicationRecord
default_scope -> { order(created_at: :desc) }
belongs_to :user
belongs_to :speaker, class_name: "Artist"
belongs_to :topic, class_name: "Artist"
validates :speaker, presence: true
validates :topic, presence: true
validates :content, presence: true, length: { maximum: 1200 }
validates :source, presence: true, length: { maximum: 60 }
validates :user_id, presence: true
end
class Artist < ApplicationRecord
default_scope -> { order(name: :asc) }
belongs_to :user
has_many :spoken_quotes, class_name: "Quote", foreign_key: :speaker_id
has_many :topic_quotes, class_name: "Quote", foreign_key: :topic_id
validates :user_id, presence: true
validates :name, presence: true, length: { maximum: 60 },
uniqueness: { case_sensitive: false }
end
表单如下所示:
<%= form_for(@quote) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<div class="form-group">
<label>Topic</label>
<%= f.collection_select :topic_id, Artist.all, :id, :name %>
</div>
<div class="form-group">
<label>Speaker</label>
<%= f.collection_select :speaker_id, Artist.all, :id, :name %>
</div>
<div class="form-group">
<%= f.text_area :content, class: "form-control",
placeholder: "Share a new quote..." %>
</div>
<div class="form-group">
<%= f.url_field :source, class: "form-control",
placeholder: "http:// Link to your source" %>
</div>
</div>
<%= f.submit "Post", class: "btn btn-primary btn-block" %>
<% end %>
首先,我尝试将这些验证添加到报价模型中:
validates :speaker, uniqueness: {scope: :topic}
validates :topic, uniqueness: {scope: :speaker}
这在第一次起作用,但一旦你尝试在第二次引用中重复使用艺术家作为演讲者或主题,例如,分享Lou Reed所说的关于David Bowiee以外的其他人的引用,这将验证Lou Reed的独特性,并且不会让我在第二次引用中重复使用Lou Reed,因为他在第一次引用中已经被用作演讲者。这不是预期的行为,因此接下来我尝试将其添加到报价模型中:
validates :speaker, presence: true, uniqueness: true, if: :speaker_and_topic_are_the_same?
def speaker_and_topic_are_the_same?
:topic_id == :speaker_id
end
这种方法背后的思想是,只有当说话人和主题在同一形式上相同时,它才会强制进行唯一性验证。
但不幸的是,这不起作用,让我可以创建一个引语,其中演讲者和主题是同一位艺术家。
那么,在rails中实施这种验证的正确方法是什么呢?