验证表单中是否存在嵌套属性

Validate presence of nested attributes within a form

我有以下联想:

#models/contact.rb
class Contact < ActiveRecord::Base
  has_many :contacts_teams
  has_many :teams, through: :contacts

  accepts_nested_attributes_for :contacts_teams, allow_destroy: true
end

#models/contacts_team.rb
class ContactsTeam < ActiveRecord::Base
  belongs_to :contact
  belongs_to :team
end

#models/team.rb
class Team < ActiveRecord::Base
  has_many :contacts_team
  has_many :contacts, through: :contacts_teams
end

A contact 应始终至少有一个关联的团队(在 contacts_teams 的富连接 table 中指定)。

如果用户试图在没有关联团队的情况下创建联系人:应该抛出验证。如果用户试图删除联系人的所有关联团队:应抛出验证。

我该怎么做?

我确实看过 nested attributes docs. I also looked at this article and this article 这两个都有点过时了。

完成:我正在使用 nested_form_fields gem 将新的关联团队动态添加到联系人。这是表格上的相关部分(有效,但目前无法验证至少有一个团队与联系人相关联):

<%= f.nested_fields_for :contacts_teams do |ff| %>
  <%= ff.remove_nested_fields_link %>
  <%= ff.label :team_id %>
  <%= ff.collection_select(:team_id, Team.all, :id, :name) %>
<% end %>
<br>
<div><%= f.add_nested_fields_link :contacts_teams, "Add Team"%></div>

因此,当 "Add Team" 未被单击时,与团队相关的参数不会传递任何内容,因此不会创建 contacts_team 记录。但是当单击 "Add Team" 并选择一个团队并提交表单时,像这样的东西会通过参数传递:

"contacts_teams_attributes"=>{"0"=>{"team_id"=>"1"}}

文档建议使用 reject_if 并将其传递给 proc:

accepts_nested_attributes_for :posts, reject_if: proc { |attributes| attributes['title'].blank? }

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

这会对创建和更新 contact 进行验证:确保至少有一个关联 contacts_team。当前存在导致糟糕的用户体验的边缘情况。 I posted that question here。在大多数情况下,这可以解决问题。

#custom validation within models/contact.rb
class Contact < ActiveRecord::Base
  ...
  validate :at_least_one_contacts_team

  private
  def at_least_one_contacts_team
    # when creating a new contact: making sure at least one team exists
    return errors.add :base, "Must have at least one Team" unless contacts_teams.length > 0

    # when updating an existing contact: Making sure that at least one team would exist
    return errors.add :base, "Must have at least one Team" if contacts_teams.reject{|contacts_team| contacts_team._destroy == true}.empty?
  end           
end

在 Rails 5 中可以使用:

validates :contacts_teams, :presence => true

如果你有一个 Profile 模型嵌套在一个 User 模型中,并且你想验证嵌套模型,你可以这样写:(你还需要 validates_presence_of 因为 validates_associated 没有'如果用户没有任何关联的配置文件,则 t 验证配置文件)

class User < ApplicationRecord

  has_one :profile
  accepts_nested_attributes_for :profile
  validates_presence_of :profile
  validates_associated :profile

型号名称: 1:审批 2: approval_sirs

协会: 1:审批 has_many :approval_sirs, :foreign_key => 'approval_id', :dependent => :destroy accepts_nested_attributes_for :approval_sirs, :allow_destroy => 真 2: approval_sirs
belongs_to:批准,:foreign_key => 'approval_id'

在approvals.rb ## 嵌套表单验证 验证:mandatory_field_of_demand_report_sirs

private

def mandatory_field_of_demand_report_sirs
    self.approval_sirs.each do |approval_sir|
        unless approval_sir.marked_for_destruction?
          errors.add(:base, "Demand Report Field are mandatory in SIRs' Detail") unless approval_sir.demand_report.present?
        end
    end
end