0

我的 Rails 应用中有模型:

拥有_many Swots 的Sales_Opportunity。

我正在使用 FactoryGirl 设置它们并运行测试以显示当我删除我的 Sales_Opportunity 时,我也会删除相关的 Swots。出于某种原因,在使用 Byebug 进行调试时,我得到了奇怪的结果——Sales_Opportunity 和 Swot 记录正在正确创建,但是当我运行 sales_opportunity.swots 它返回 [ ] 而 sales_opportunity.swots.count 返回 1。更奇怪的是确切的相同的代码适用于花药对象关联(timeline_events 与 swot 完全一样,但适用于相同的代码)。

谁能告诉我我做错了什么?

Sales_Opportunity.rb:

class SalesOpportunity < ActiveRecord::Base
 default_scope { order('close_date ASC') }
 belongs_to :user
 belongs_to :company
 has_many :key_contacts
 has_many :timeline_events, dependent: :destroy
 has_many :swots, dependent: :destroy
end

Swot.rb:

class Swot < ActiveRecord::Base
 belongs_to :sales_opportunity
 validates :swot_details, presence: true
 validates :sales_opportunity_id, presence: true
 enum swot_type: [:strength, :weakness, :opportunity, :threat]
 enum swot_importance: { minimal: 1, marginal: 2, noteworthy: 3, significant: 4, critical: 5 }
 validates :swot_importance, presence: true
end

Swot FactoryGirl 规格:

FactoryGirl.define do
factory :swot do
    swot_importance             "minimal"
    swot_details                "Some boring details"
    swot_type                   "threat"

    trait :attached do
        association             :sales_opportunity, :with_user_id
    end
 end
end

Sales_Opportunity FactoryGirl 规格:

FactoryGirl.define do
sequence(:opportunity_name) { |n| "Sales Oppotunity - #{n}" }

factory :sales_opportunity do
    user
    opportunity_name {generate(:opportunity_name)}
    close_date                  "2014/12/12"
    sale_value                  10000
    company_id                  7

    trait :with_user_id do
        user_id                     6
    end
end
end

失败的 Rspec 测试:

describe "when swot's parent sales opportunity is destroyed" do
    let(:swot) { FactoryGirl.create(:swot, :attached) }
    let(:sales_opportunity) { swot.sales_opportunity }

it "should destroy associated swots" do
    dswots = sales_opportunity.swots.to_a
    byebug
    sales_opportunity.destroy
    expect(dswots).not_to be_empty
    dswots.each do |dswot|
    expect(Swot.where(id: dswot.id)).to be_empty
  end
end
  end

记录 swot 时控制台的输出(byebug):

#<Swot id: 13, swot_type: 3, swot_importance: 1, sales_opportunity_id: 564, swot_details: "Some boring details", created_at: "2015-07-27 10:57:23", updated_at: "2015-07-27 10:57:23">

记录 sales_opportunity 时控制台的输出:

#<SalesOpportunity id: 564, close_date: "2014-12-12 00:00:00", user_id: 6, created_at: "2015-07-27 10:57:23", updated_at: "2015-07-27 10:57:23", pipeline_status: 0, opportunity_name: "Sales Oppotunity - 4", company_id: 7, sale_value: #<BigDecimal:7fe9ffd25078,'0.1E5',9(27)>, swot_score: 0>

sales_opportunity.swots.count 的输出:

(byebug) sales_opportunity.swots.count
 1

sales_opportunity.swots 的输出:

(byebug) sales_opportunity.swots
#<ActiveRecord::Associations::CollectionProxy []>

我想我已经包含了所有已知的信息。sales_opportunities 和 Swots/Timeline_Events 之间的 Rspec 测试、FactoryGirl 工厂和设置完全相同 - 但 Timeline_Events 的 Rspec 测试通过,而 collection_proxy 适用于这些测试(据我所知,代码是相同的):

Timeline_Event 工厂:

FactoryGirl.define do
factory :timeline_event do
    activity                    "Some activity"
    due_date                    "2014/11/11"

    trait :attached do
        association             :sales_opportunity, :with_user_id
    end
end
end

工作 Rspec 测试:

describe "when sales opportunity is destroyed for timeline event" do
    let(:timeline_event) { FactoryGirl.create(:timeline_event, :attached) }
    let(:sales_opportunity) { timeline_event.sales_opportunity }

it "should destroy associated timeline events" do
    timeline_events = sales_opportunity.timeline_events.to_a
    sales_opportunity.destroy
    expect(timeline_events).not_to be_empty
    timeline_events.each do |event|
    expect(TimelineEvent.where(id: event.id)).to be_empty
  end
end
end

Timeline_Event.rb:

class TimelineEvent < ActiveRecord::Base
 belongs_to :sales_opportunity
 validates :activity, presence: true 
 validates :due_date, presence: true
 validates :sales_opportunity_id, presence: true
end

当在这里的同一个地方运行 byebug 时,我得到一个包含 Timeline_Event 的数组。

谁能帮我理解我的代码出了什么问题?

谢谢。

4

2 回答 2

1
RSpec.describe SalesOpportunity, type: :model do

  let(:sales_opportunity) { create(:sales_opportunity) }

  describe "swots" do
    let!(:swot) { create(:swot, sales_opportunity: sales_opportunity) }

    it "destroys nested swots" do
      sales_opportunity.destroy
      swot.reload
      expect(swot.destroyed?).to be_truthy
    end
  end
end

Note that i'm adding this to the SalesOpportunity spec, because the dependant destroy behavior belongs to SalesOpportunity not the child association.

Edit.

Another way to write this spec would be:

it "destroys nested swots" do
  expect {
    sales_opportunity.destroy
  }.to change(Swot, :count).by(-1)
end
于 2015-07-27T13:03:07.323 回答
1

我解决了这个问题 - 似乎需要重新加载 sales_opportunity 才能保持 Active Record 关联。这个答案是解决问题的关键。

这是工作代码:

    describe "when swot's parent sales opportunity is destroyed" do
     let!(:swot) { FactoryGirl.create(:swot, sales_opportunity: sales_opportunity) }

it "should destroy associated swots" do
    sales_opportunity.reload
    expect { sales_opportunity.destroy }.to change(sales_opportunity.swots, :count).by(-1)
 end
end

使用上面 Max 回答的一些元素也帮助我改进了代码的外观和感觉。

于 2015-07-28T02:09:26.587 回答