実現したいこと、前提
自分でアプリを作っていて、
常設の商品が置いてあって
購入ページに行って、商品を購入するために必要な情報を入力して、購入ボタンをクリックしたら購入完了ページが表示される。と言った結合テストを書いてます。
そこのテストをパスしたいです。
詳しくは以下を参考にして欲しいのですが、
idが6番のuserに商品を投稿してもらって、user_idが6番の投稿は、常設の商品として、置いてあって、それ以外は一般ユーザーの投稿みたいなコードです。
こんな感じで一般ユーザーの投稿と購入するページの商品の構造が一緒なので、クソコードになりました。
エラー内容
私の行った手順は以下です。
docker-compose exec web bundle exec rspec spec/system/trade_addresses_spec.rb
すると、以下のような結果になりました。
TradeAddresses 購入ができる時 必須項目を入力 (FAILED - 1) 購入ができない時 ログインしてないと購入ページに行っても、ログインページにリダイレクト 必須情報の抜け漏れ Failures: 1) TradeAddresses 購入ができる時 必須項目を入力 Failure/Error: @drinks = @admin_user.drinks.paginate(page: params[:page],per_page: 10) NoMethodError: undefined method `drinks' for nil:NilClass # ./app/controllers/sold_drinks_controller.rb:5:in `index' Finished in 2.78 seconds (files took 4.39 seconds to load) 3 examples, 1 failure Failed examples: rspec ./spec/system/trade_addresses_spec.rb:22 # TradeAddresses 購入ができる時 必須項目を入力 ERROR: 1
controllers/sold_drinks_controller.rb
class SoldDrinksController < ApplicationController def index @admin_user = User.find_by(id: 6) @drinks = @admin_user.drinks.paginate(page: params[:page],per_page: 10) @title = "商品を購入する" end end
のdrinksの中身が無いので起こってるエラーだと思います。
NoMethodError: undefined method `drinks' for nil:NilClass # ./app/controllers/sold_drinks_controller.rb:5:in `index'
該当のソースコード
私のgithubです
spec/system/trade_addresses_spec.rb
require 'rails_helper' RSpec.describe "TradeAddresses", type: :system do before do @user = FactoryBot.create(:user) @trade_address = FactoryBot.build(:trade_address) @admin_user = User.new(id: 6, email: "hoge@gmail.com", password: "hogehoge", password_confirmation: "hogehoge", activated: true) drinks = FactoryBot.build(:sold_drink,user_id: @admin_user.id) # @drinks = @admin_user.drinks.paginate(page: params[:page],per_page: 10) # NoMethodError: # undefined method `drinks' for nil:NilClass end context "購入ができる時" do it "必須項目を入力" do # ログイン visit login_path fill_in 'email', with: @user.email fill_in 'password', with: @user.password find('input[name="commit"]').click expect(current_path).to eq(user_path(@user)) expect(page).to have_content('商品を購入') # 商品一覧ページに遷移 visit buy_path # 購入ページに遷移 visit drink_trades(@drink) # その商品の写真が表示される # その商品の名前が表示される # その商品の値段が表示される # 必須項目を入力 fill_in 'card-number' ,with: '4242424242424242' fill_in 'card-exp-month' ,with: 12 fill_in 'card-exp-year' ,with: 24 fill_in 'card-cvc' ,with: 123 fill_in 'fam_name' ,with: @trade_address.fam_name fill_in 'first_name' ,with: @trade_address.first_name fill_in 'fam_name_kana' ,with: @trade_address.fam_name_kana fill_in 'first_name_kana' ,with: @trade_address.first_name_kana select '1960', from: 'trade_address[birthday(1i)]' select '8', from: 'trade_address[birthday(2i)]' select '19', from: 'trade_address[birthday(3i)]' fill_in 'postal-code' ,with: @trade_address.postal_code select '北海道', form: 'trade_address[prefecture]' fill_in 'postal-code' ,with: @trade_address.postal_code fill_in 'city' ,with: @trade_address.city fill_in 'addresses' ,with: @trade_address.address fill_in 'phone-number' ,with: @trade_address.phone_num # 購入するをクリック expect{ find('input[name="commit"]').click }.to change { Trade.count }.by(1) # 購入完了ページに遷移 expect(page).to have_content("商品をご購入いただきありがとうございます! ") end end
spec/factories/drinks.rb
FactoryBot.define do factory :drink do # class: モデル名 ってやる必要あるが、キー名で推測してるらしい name {"TOKYOロースト"} price {350} explain {"これはコーヒーの説明です"} region_id {2} body_id {Body.all.sample} acidity_id {Acidity.all.sample} processing_id {Processing.all.sample} likes_count {2} association :user association :region association :body association :acidity association :processing after(:build) do |drink| drink.image.attach(io: File.open('app/assets/images/ethiopia.jpg'), filename: 'ethiopia.jpg') end end factory :sold_drink ,class: Drink do name {"TOKYOロースト"} price {350} explain {"これはコーヒーの説明です"} region_id {2} body_id {Body.all.sample} acidity_id {Acidity.all.sample} processing_id {Processing.all.sample} likes_count {2} user_id {6} association :user association :region association :body association :acidity association :processing after(:build) do |drink| drink.image.attach(io: File.open('app/assets/images/ethiopia.jpg'), filename: 'ethiopia.jpg') end end end
controllers/sold_drikns_controller.rb
class SoldDrinksController < ApplicationController def index @admin_user = User.find_by(id: 6) @drinks = @admin_user.drinks.paginate(page: params[:page],per_page: 10) # ↑ここでエラーが起きてます。 @title = "商品を購入する" end end
試したこと
factory :sold_drink ,class: Drink do name {"TOKYOロースト"} price {350} explain {"これはコーヒーの説明です"} region_id {2} body_id {Body.all.sample} acidity_id {Acidity.all.sample} processing_id {Processing.all.sample} likes_count {2} user_id {6} association :user association :region association :body association :acidity association :processing after(:build) do |drink| drink.image.attach(io: File.open('app/assets/images/ethiopia.jpg'), filename: 'ethiopia.jpg') end end
このようにfactorybotを定義して、
user_idが6のdrinksは商品として登録されるので、このようなコードを書いたり、
spec/system/trade_addresses_spec.rb
@admin_user = User.new(id: 6, email: "hoge@gmail.com", password: "hogehoge", password_confirmation: "hogehoge", activated: true) drinks = FactoryBot.build(:sold_drink,user_id: @admin_user.id)
とかを定義したり、
@drink = Drink.new( name: "商品", price: 340, explain: "商品の説明", user_id: 6, image: ActiveStorage::Blob.create_and_upload!(io: File.open("app/assets/images/break_first.jpg"),filename: "breake_first.jpg") )
このように書いたら,user_idが6のdrink(商品)ができたので、
いけると思ったのですが、エラー内容は変わらずでした。
@admin_user => #<User:0x0000561921546128 id: 6, nickname: nil, email: "hoge@gmail.com", created_at: nil, updated_at: nil, password_digest: [FILTERED], remember_digest: nil, activation_digest: nil, activated: true, activated_at: nil>
@admin_userもしっかり定義されてるように感じます。
なお、私の環境は以下の通りです。
Docker version 20.10.5,mac catalina 10.15.7
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。