我试图登录一个用户并访问该用户拥有的记录的页面.

RSpec.describe 'User matters', type: :system do
  context 'urgent matter flow' do
    let!(:matter) { create(:matter, :with_order) }

    before :each do
      login_as(matter.patient.user) # warden helper
    end

    it 'can submit matter info' do
      visit users_matter_path(matter)
    end
  end
end

控制器是一个简单的查找

def show
  @matter = current_user.patient.matters.find(params[:id])
  @order = @matter.orders.joins(:order_items).first
end

Error in the template:

<%= @matter.id # works %> 
<%= @order.id # undefined method `id' for nil:NilClass %>

工厂:

FactoryBot.define do
  factory :matter do
    overview_image { Rack::Test::UploadedFile.new('spec/fixtures/images/bandit.jpg', 'image/jpeg') }
    overview2_image { Rack::Test::UploadedFile.new('spec/fixtures/images/bandit.jpg', 'image/jpeg') }
    patient
    doctor

    trait :with_order do
      after(:create) do |matter|
        create_list(:order, 1, matter: matter)
      end
    end
  end

  # -- Order ------------------
  factory :order do
    matter

    status { :placed }
    currency_code { 'SEK' }
  end

  # -- User -------------------
  sequence :user_email do |index|
    "patient-#{Random.hex(4)}#{index}@gmail.com"
  end

  factory :user do
    email { generate(:user_email) }
    locale { 'en' }
    country_alpha2_code { 'SE' }
    mobile_number { '+46701234567' }
    password { Faker::Internet.password(min_length: 8, max_length: 20) }
    password_confirmation { "#{password}" }
    after(:create) do |user|
      user.patient ||= create(:patient, user: user)
    end
  end

  # -- Patient -----------------
  sequence :patient_id_number do |index|
    year = index.to_s.rjust(2, '0')
    "19#{year}01019876"
  end

  factory :patient do
    id_number { generate(:patient_id_number) }
    date_of_birth { '1990-01-01' }
    first_name { 'John' }
    last_name { 'Doe' }

    user
  end
end

Rails_helper.rb(省略了一些不必要的内容)

require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'

require 'rspec/rails'

Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

RSpec.configure do |config|
  config.include Warden::Test::Helpers

  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :system) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.append_after(:each) do
    DatabaseCleaner.clean
  end

  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!
end

以及spec_helper.rb(省略了一些不必要的内容)

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
    expectations.syntax = :expect
  end

  config.before(:each, type: :system) do
    driven_by :selenium
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
  config.shared_context_metadata_behavior = :apply_to_host_groups
  config.filter_run_when_matching :focus
  config.profile_examples = 10
  config.order = :random
end

这一切为什么要发生?将use_transactional_fixtures设置为false难道不正是这件事的目的吗?

PS:我想测试整个用户流,有多个步骤.能够预先创建与某些州及其关系的记录,速度会快得多.

-更新:

在运行RSpec时,我跟踪了test.log并看到以下输出:

Matter Create (0.3ms)  INSERT INTO "matters" ("patient_id", "doctor_id", "reference", "symptoms", "tags", "status", "diagnosis", "planned_action", "orders_count", "matter_comments_count", "matter_responses_count", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING "id"  [["patient_id", "ed1c0576-78a4-4383-ac33-291ca44083ca"], ["doctor_id", "cdab5e14-3641-4a78-8de6-1a0056635e73"], ["reference", "pohmb"], ["symptoms", nil], ["tags", nil], ["status", "created"], ["diagnosis", nil], ["planned_action", nil], ["orders_count", 0], ["matter_comments_count", 0], ["matter_responses_count", 0], ["created_at", "2023-11-18 09:08:57.796995"], ["updated_at", "2023-11-18 09:08:57.796995"]]


  Order Create (0.3ms)  INSERT INTO "orders" ("matter_id", "reference", "currency_code", "status", "order_items_count", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["matter_id", "8533289a-4087-4664-9fe3-df4bc7a9e241"], ["reference", "evt0o"], ["currency_code", "SEK"], ["status", 0], ["order_items_count", 0], ["created_at", "2023-11-18 09:08:57.841842"], ["updated_at", "2023-11-18 09:08:57.841842"]]

因此,这些记录正在正确创建.我还验证了matter_id(8533289a-4087-4664-9fe3-df4bc7a9e241)是相同的.

因此,我认为这可能与RSpec/系统测试和事务未提交有关?

推荐答案

查看您的工厂和日志(log)就会发现,您没有创建任何OrderItem,这意味着当您try 加入订单时,不会返回任何内容:

@matter.orders.joins(:order_items).first

此外,我认为你混淆了joinsincludes,因为我不明白为什么你需要加入,而不是仅仅:

@matter.orders.first

# which should give the same result as
@matter.orders.left_joins(:order_items).first

举例说明:

>> Order.all
=> [#<Order:0x00007f6795badfc0 id: 1>, #<Order:0x00007f6795bade80 id: 2>]

>> Order.joins(:order_items)
=> [#<Order:0x00007f67985cb690 id: 1>, #<Order:0x00007f67985cb410 id: 1>]
# NOTE: the dup orders             ^                                  ^
#       first Order has two OrderItems
#       second Order has no OrderItems so it is not in the result

>> Order.left_joins(:order_items)
=> [#<Order:0x00007f6795af6a50 id: 1>, #<Order:0x00007f6795af6910 id: 1>, #<Order:0x00007f6795af67d0 id: 2>]

first相同:

>> Order.first
=> #<Order:0x00007f6798891410 id: 1>

>> Order.joins(:order_items).first
=> #<Order:0x00007f6798891410 id: 1>

>> Order.left_joins(:order_items).first
=> #<Order:0x00007f6798891410 id: 1>

如果要预加载order_items,请使用includes:

>> Order.includes(:order_items)
=> [#<Order:0x00007f6795d9c598 id: 1>, #<Order:0x00007f6795d9c458 id: 2>]
# NOTE: no duplicates, all orders are loaded

>> Order.includes(:order_items).to_a.first.instance_variable_get("@association_cache")
=> 
{:order_items=>
  #<ActiveRecord::Associations::HasManyAssociation:0x00007f679799d710
...
   @stale_state=nil,
   @target=[#<OrderItem:0x00007f6795acd5d8 id: 1, order_id: 1>, #<OrderItem:0x00007f6795acd498 id: 2, order_id: 1>]>}
# NOTE: ^ order_items are preloaded into each Order object to avoid n+1 issues

Ruby-on-rails相关问答推荐

在Ruby on rails中,重复访问ActiveRecordModel返回相同的对象:预期行为还是错误?

获取所有属于模型的嵌套对象

如何在 Rails 中声明动态路由范围/命名空间变量?

为什么 Rails 执行器不能识别内核的改进?

如何在 Rails 中注释掉 ERB?

Rails - 如何使用子对象的嵌套属性和强参数填充父对象ID?

为特定操作使用布局

Rails 100% 新手问题 - send() 方法

键入rails 控制台无法启动?

使用rails form_for时带有_path的未定义方法

如何将实例变量传递给 RSpec 共享示例

rails select标签,预先 Select 了多个值

Rails 将 form_for 对象传递给部分

使用 SQLite 3 将 RoR 应用程序部署到 Heroku 失败

如何从 ActiveRecord 中的每个组中获取最新记录?

如何在 Rails 中验证日期以使其在今天之后?

在 Rails 生产中禁用assets资源 缩小

ActiveRecord 查找现有表索引

rails 单数资源还是复数?

在 Rails 3 中设置会话超时