Rails 5 验证失败:志愿者默认事件必须存在....但为什么会这样以及如何做到这一点

Rails 5 Validation failed: Volunteer default event must exist....but why this and how to make it so

我正在将旧应用重建为 Rails 5.

所以我收到一个错误,我不知道为什么。我不完全确定它在要求什么。这是要求修改模型关联吗?我在下面包含了我的模型关联,如果我需要包含任何其他内容来帮助破译此错误,请告诉我。

  binding.pry

    vs.set_values_if_stuck
    vs.assignments = []
    @success = a.valid? && vs.save
    # [1] pry(#<VolunteerEventsController>)> vs.set_values_if_stuck
    #   Roster Load (0.3ms)  SELECT  "rosters".* FROM "rosters" WHERE "rosters"."id" =  LIMIT   [["id", 7], ["LIMIT", 1]]
    # VolunteerEvent Load (0.3ms)  SELECT  "volunteer_events".* FROM "volunteer_events" WHERE "volunteer_events"."description" =  AND "volunteer_events"."date" =  LIMIT   [["description", "Roster #7"], ["date", "2021-01-11"], ["LIMIT", 1]]
    # (0.1ms)  BEGIN
    # (0.1ms)  ROLLBACK
    # (0.1ms)  BEGIN
    # (0.1ms)  ROLLBACK
    # ActiveRecord::RecordInvalid: Validation failed: Volunteer default event must exist

模特协会

class Assignment < ApplicationRecord
  belongs_to :volunteer_shift
  has_one :volunteer_task_type, :through => :volunteer_shift, :source => :volunteer_task_type
  belongs_to :contact ,optional: true
  validates_presence_of :volunteer_shift #belongs_to takes care of this now
  validates_associated :volunteer_shift
  belongs_to :attendance_type
  belongs_to :call_status_type
  validates_presence_of :set_date, :if => :volshift_stuck #belongs_to takes care of this now??

  delegate :set_date, :set_date=, :to => :volunteer_shift
  delegate :set_description, :set_description=, :to => :volunteer_shift

  has_one :contact_volunteer_task_type_count, lambda{||
    {:conditions => 'contact_volunteer_task_type_counts.contact_id = #{defined?(attributes) ? contact_id : "assignments.contact_id"}', :through => :volunteer_shift, :source => :contact_volunteer_task_type_counts}
  }
  scope :date_range, lambda { |range|
    joins(volunteer_shift: :volunteer_event)
        .where(volunteer_shifts: { volunteer_events: { date: range } })
  }
  scope :is_after_today, lambda {||
    { :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) > ?', Date.today] }
  }
  scope :on_or_after_today, lambda {||
    { :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) >= ?', Date.today] }
  }
  scope :not_cancelled, -> { where('(attendance_type_id IS NULL OR attendance_type_id NOT IN (SELECT id FROM attendance_types WHERE cancelled = \'t\'))')}
  scope :roster_is_limited_by_program, -> {where("roster_id IN (SELECT id FROM rosters WHERE limit_shift_signup_by_program = 't')").joins(:volunteer_shift)}
...
end
class Roster < ApplicationRecord
  has_and_belongs_to_many :skeds
  belongs_to :contact_type
  scope :enabled, -> {where(['enabled = ?', true])}
  has_many :volunteer_shifts
  has_many :volunteer_default_shifts
  belongs_to :restrict_from_sked, :class_name => "Sked"

  def sandbox?
    name.downcase == 'sandbox'
  end

  def Roster.auto_generate_all
    fails = []
    if Roster.are_auto_generated?
      Roster.enabled.reject(&:sandbox?).each do |r|
        start_d = r.generated_to_date + 1
        end_d = Date.today + eval(Default["autogenerate_volskedj_out"])
        fails = fails + r.auto_generate(start_d, end_d) if start_d <= end_d
      end
    end
    return fails
  end

  def generated_to?(d)
    generated_to_date >= d
  end

  def to_s
    name
  end

  def generated_to_date
    newc = Conditions.new
    newc.apply_conditions({})
    newc.roster_enabled = true
    newc.roster_id = self.id
    newc.generated_shift_enabled = true
    d1 = VolunteerEvent.maximum(:date, :conditions => newc.conditions(Assignment), :joins => 'INNER JOIN "volunteer_shifts" ON volunteer_shifts.volunteer_event_id = volunteer_events.id INNER JOIN "assignments" ON assignments.volunteer_shift_id = volunteer_shifts.id LEFT OUTER JOIN "attendance_types" ON "attendance_types".id = "assignments".attendance_type_id')
    d2 = VolunteerEvent.maximum(:date, :conditions => newc.conditions(ResourcesVolunteerEvent), :joins => 'INNER JOIN "resources_volunteer_events" ON resources_volunteer_events.volunteer_event_id = volunteer_events.id')
    return [d1, d2, Date.today].select{|x| !!x}.max
  end

  def auto_generate(from, to)
    results = []
    begin
      c = Conditions.new
      c.apply_conditions({})
      c.roster_enabled = true
      c.roster_id = self.id
      conflicts = VolunteerDefaultShift.find_conflicting_assignments(from, to, c)
      skippers = conflicts.map{|x| x[1].id}
      results = conflicts.map{|x| "On #{x[0]}, #{x[1].contact.display_name} (##{x[1].contact_id}) was not successfully scheduled for #{x[1].slot_type_desc} (#{self.name} roster) as they have the following conflicting shifts: #{x[2].map{|x| x.description}.join(" ")}"}
      VolunteerDefaultShift.generate(from, to, c, skippers)
      ResourcesVolunteerDefaultEvent.generate(from, to, c)
    rescue => e
      puts "ERROR: Failed to generate #{self.name} roster from #{from} to #{to}!"
      puts "Please check for consistency,"
      puts "  error message: #{e.to_s}"
    end
    results
  end

  def Roster.are_auto_generated?
    ! Default["autogenerate_volskedj_out"].nil?
  end

  def skeds_s
    self.skeds.map(&:name).sort.join(", ")
  end

  # note: #Keep this here so know where to find the deprecation info - Fonso
  # THIS is where date value from add new record form gets inserted into a new record
  def vol_event_for_date(date)
    binding.pry
    # VolunteerEvent.find_or_create_by_description_and_date("Roster ##{self.id}", date) <-- original
    # https://guides.rubyonrails.org/4_0_release_notes.html#active-record-deprecations
    VolunteerEvent.find_or_create_by(description: "Roster ##{self.id}", date: date)
    binding.pry
  end

  def vol_event_for_weekday(wday)
    # VolunteerDefaultEvent.find_or_create_by_description_and_weekday_id("Roster ##{self.id}", wday) <-- original
    # https://guides.rubyonrails.org/4_0_release_notes.html#active-record-deprecations
    VolunteerDefaultEvent.find_or_create_by(description: "Roster ##{self.id}", weekday_id: wday)
  end
end

class VolunteerEvent < ApplicationRecord
  belongs_to :volunteer_default_event
  validates_presence_of :date
  has_many :volunteer_shifts, :dependent => :destroy
  has_many :resources_volunteer_events, :dependent => :destroy
  validates_associated :volunteer_shifts
...
end
class VolunteerShift < ApplicationRecord
  validates_presence_of :roster_id
  validates_presence_of :end_time
  validates_presence_of :start_time
  has_many  :assignments
  belongs_to :volunteer_default_shift
  belongs_to :volunteer_task_type
  belongs_to :roster
  belongs_to :volunteer_event
  belongs_to :program
  has_many :contact_volunteer_task_type_counts, :primary_key => 'volunteer_task_type_id', :foreign_key => 'volunteer_task_type_id' #:through => :volunteer_task_type

...
end

感谢您的宝贵时间

在你的VolunteerEvent中你有这条线

belongs_to :volunteer_default_event

自 Ruby 在 Rails 5.0 以来,belongs_to 关联的默认设置是它们必须存在才能使记录有效(参见 article about this behavior)。这基本上意味着每次你定义一个像 belongs_to :foo 这样的关联时,都会自动添加一个 validates_presence_of :foo

您有解决问题的方法:

  1. 您确保将 volunteer_default_event 设置为有效事件。或者

  2. 您将关联标记为可选,这意味着当没有 volunteer_default_event 时可以吗?可以这样做:

    belongs_to :volunteer_default_event, optional: true