Factory Girl,InvalidRecord错误问题

5
我遇到一个错误问题:

我遇到了一个错误问题:

ActiveRecord::RecordInvalid

由于这个引起的:
let(:ind2){ build(:ind2) }

Rspec测试:

  describe '#client_free_time_validation' do
    let(:ind) { build(:ind).tap {|e| p e.valid?; p e.errors}}
    let(:ind2){ build(:ind2).tap {|e| p e.valid?; p e.errors} }

    context 'when training is during another training' do
      it 'raises an error' do
        expect(ind.valid?).to be_truthy
        expect(ind2.valid?).to be_falsey
        # expect(ind2.errors.count).to eq 1
        # expect(ind2.errors[:base]).to eq(['Masz w tym czasie inny trening.'])
      end
    end

工厂:

FactoryGirl.define do
  factory :individual_training do
    date_of_training { Date.today.next_week.advance(days: 1) }
    association :client, factory: :client
    association :trainer, factory: :trainer
    start_on Time.parse('12:30')
    end_on Time.parse('13:30')
    association :training_cost, factory: :tc2

    factory :ind do
      start_on Time.parse('11:00')
      end_on Time.parse('12:00')
    end

    factory :ind2 do
      start_on Time.parse('10:30')
      end_on Time.parse('11:30')
    end
  end
end

我感到困惑,因为在另一个测试中类似的 let 能够正常工作。我尝试使用 tap 方法进行调试,但它并没有显示错误信息(在另一种情况下会有良好的表现)。

如果需要添加一些额外的数据(例如我的模型是什么样子等),请写下来。

我注意到,如果我注释掉第一个 let 或第二个 let,测试就能通过。这看起来像是两个 letindind2)不能同时工作的情况。测试生成的属性示例值如下:

#<ActiveModel::Errors:0x00000001f4ade8 @base=#<IndividualTraining id: nil, date_of_training: "2016-08-23", client_id: 28, trainer_id: 29, start_on: "2016-08-20 11:00:00", end_on: "2016-08-20 12:00:00", training_cost_id: 4>, @messages={}>

您有什么建议可以调试哪个记录无效?

更新:

完整的错误信息:

Failure/Error: let(:ind2){ build(:ind2).tap {|e| p e.valid?; p e.errors} }

 ActiveRecord::RecordInvalid:
   Nieprawidłowy rekord

# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/validations.rb:79:in `raise_record_invalid'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/validations.rb:43:in `save!'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:291:in `block in save!'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:220:in `transaction'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:291:in `save!'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/configuration.rb:18:in `block in initialize'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluation.rb:15:in `create'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:12:in `block in result'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:9:in `tap'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:9:in `result'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory.rb:42:in `run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.5.1/lib/active_support/notifications.rb:166:in `instrument'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:28:in `run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/build.rb:5:in `association'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:31:in `association'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute/association.rb:19:in `block in to_proc'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:75:in `instance_exec'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:75:in `block in define_attribute'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:56:in `get'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:16:in `block (2 levels) in object'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:15:in `each'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:15:in `block in object'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:14:in `tap'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:14:in `object'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluation.rb:12:in `object'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/build.rb:9:in `result'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory.rb:42:in `run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.5.1/lib/active_support/notifications.rb:166:in `instrument'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:28:in `run'
     # /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
     # ./spec/models/individual_training_spec.rb:60:in `block (3 levels) in <top (required)>'
     # ./spec/models/individual_training_spec.rb:65:in `block (4 levels) in <top (required)>'

更新2:

当我在工厂中设置date_of_training Date.today时,错误消失了。我还尝试手动设置日期,如2016-08-23,但仍然是InvalidRecord。同时Date.today + 1.day也不起作用。有什么想法可以解决吗?也许date_of_training不是直接的问题。

更新3: IndividualTraining模型验证:

  private

  def date_and_start_on_validation
    unless start_on.blank?
      if date_of_training < Date.today
        errors.add(:base, 'You cannot set individual training before today.')
      elsif date_of_training == Date.today
        if start_on <= Time.now
          errors.add(:base, 'Time of today training is before current time.')
        end
      end
    end
  end

  # check if trainer work while will be individual_training
  def date_of_training_validation
    unless start_on.blank?
      trainer.work_schedules.each_with_index do |ti, ind|
        if ti.day_of_week == BackendController.helpers.translate_date(date_of_training)
          if (start_on.strftime('%H:%M')..end_on.strftime('%H:%M'))
             .overlaps?(ti.start_time.strftime('%H:%M')..ti.end_time.strftime('%H:%M'))
            break
          else
            errors.add(:base, 'Training is outside of trainer work schedule.')
          end
        elsif ind == trainer.work_schedules.size - 1
          errors.add(:base, 'In this day trainer doesn't work.')
        end
      end
    end
  end

  # check if client doesn't have another training or activity
  def client_free_time_validation
    unless start_on.blank?
      client.individual_trainings_as_client.where(date_of_training: date_of_training)
            .where('id != ?', id).each do |ci|
        if (start_on...end_on).overlaps?(ci.start_on...ci.end_on)
          errors.add(:base, 'You have another training.')
        end
      end
      client.activities.where(day_of_week: BackendController.helpers.translate_date(date_of_training))
            .each do |ca|
        if (start_on...end_on).overlaps?(ca.start_on...end_on)
          errors.add(:base, 'You have another activity.')
        end
      end
    end
  end

更新4: 我注意到如果我先执行ind.valid?-它将为true,ind2将是RecordInvalid。但当我重新加载并检查ind2.valid?-现在它是true,ind是false。
更新5: 我在不同的上下文中分别使用了相同的let,rspec通过了。可能的原因是什么,我不能在同一个上下文中使用两个let?
IndividualTraining关联
  belongs_to :trainer, class_name: 'Person', foreign_key: 'trainer_id'
  belongs_to :client, class_name: 'Person', foreign_key: 'client_id'
  belongs_to :training_cost

客户端和训练器工厂
FactoryGirl.define do
  factory :person do
    pesel { Faker::Number.number(11) }
    first_name 'Thomas'
    last_name 'Owel'
    date_of_birth { Faker::Time.between('1970-01-01', '2000-12-31') }
    email { Faker::Internet.email }
    password { Faker::Internet.password }
    type 'Person'
  end

  factory :client, parent: :person, class: 'Client' do
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    type 'Client'
  end
  factory :trainer, parent: :person, class: 'Trainer' do
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    type 'Trainer'
    salary { Faker::Number.decimal(4, 2) }
    hiredate { Faker::Time.between('2016-01-01', '2016-04-30') }
  end
end

更新6: 在另一个上下文中,我有这个let:

let(:individual_training) { build :individual_training, trainer_id: work_schedule[:person_id] }
let(:ind2) do
  build :individual_training,
        trainer_id: work_schedule[:person_id],
        date_of_training: Date.today.next_week.advance(days: 0),
        start_on: Time.now - 1.hour,
        end_on: Time.now
end

这个很好,没有错误:RecordInvalid

你确定关联的对象是有效的吗? - Michał Szajbe
请您添加完整的错误信息,这样我们才能查看行号、文件、完整的错误信息等内容。 - kcdragon
@MichałSzajbe 是的,我确定,因为我在其他测试中检查了这些工厂。 - Prezes Łukasz
@kcdragon 的帖子已更新。如果您需要更多信息,请留言。 - Prezes Łukasz
1
请为IndividualTraining模型添加验证。 - zetetic
@zetetic的帖子已更新。 - Prezes Łukasz
1个回答

2
这可能是“无效记录错误”的原因 -
Reason - It usually happens when you use "create" and "build" together.
create method persists the instance while the build method keeps it only in memory.

首先,我建议您使用构建方法,并检查与之相关的验证。您的验证有些问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接