Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

deviseで2つのモデルに保存した時のRSpecのテストコードの書き方について

解決したいこと

Ruby on Railsにてポートフォリオ用のSNSを作成しています。
サインアップ時にユーザー登録情報を保存するusersテーブルと
ユーザーのプロフィール(名前や年齢など)を保存するprofilesテーブルを作成しました
無事、二つに分けて保存することができ、次にRSpecを用いて正常形テストコードを記述しているときにエラーが出て
解決できずに困っています。

発生している問題・エラー

NoMethodError: undefined method `valid?' for #<Hash:0x00007f979ae3c450>

該当するソースコード

models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do

  before do
    @profile_params = FactoryBot.attributes_for(:profile)
    @user = FactoryBot.attributes_for(:user).merge( @profile_params )
  end

    describe "ユーザー新規登録" do

      context '新規登録できるとき' do
        it '全ての値が正常に入力されていれば登録できる' do
          expect(@user).to be_valid
        end
      end

各Factories

factories/users.rb
FactoryBot.define do
  factory :user do
    email                 {Faker::Internet.free_email}
    password              {Faker::Lorem.characters(number: 6, min_alpha: 1, min_numeric: 1)}
    password_confirmation {password}

    trait :with_nested_instances do
      after( :create ) do |user|
        create :profile, id: user.id
      end
    end  
  end
end

factories/profiles.rb
FactoryBot.define do
  factory :profile do
    nickname        {Faker::Name.initials(number: 5)}
  end
end

自分で試したこと

そもそも各カラムの正常な値が取得できていないのでは?
と思ってコンソールを起動

Loading development environment (Rails 6.0.4.1)
[1] pry(main)> @profile_params = FactoryBot.attributes_for(:profile)
=> {:nickname=>"TDQLM"}
[2] pry(main)> @user = FactoryBot.attributes_for(:user).merge( @profile_params )
=> {:email=>"malisa.stanton@yahoo.com", :password=>"3275j8", :password_confirmation=>"3275j8", :nickname=>"TDQLM"}
[3] pry(main)> @user
=> {:email=>"malisa.stanton@yahoo.com", :password=>"3275j8", :password_confirmation=>"3275j8", :nickname=>"TDQLM"}
[4] pry(main)> @user.valid?
NoMethodError: undefined method `valid?' for #<Hash:0x00007f979ae3c450>

そもそもvalid?というmethodが定義されていない?
というエラーメッセージだと思うのですが、RSpecにてなぜvalid?が使えないのでしょうか?

最初ユーザーサインアップを作るとき、userモデルとprofileモデルで分けずにuserモデル単体で作成していたときは問題なくテストができました。

エラー分で検索をかけてみてもメソッドが定義されていないということしか見つけられずにどうしたらいいか悩んでいます。
どうか助言をお願いいたします。

0

1Answer

@user = FactoryBot.attributes_for(:user).merge( @profile_params )
# こうするとわかりやすいかも
p "=" * 20
p @user
p @user.class
p "=" * 20

これはただ単にHashを作ってるだけでは?

普通はspec/factories/users.rbとかにファクトリークラスがあって、それを

user = FactoryBot.build(:user)
# user = FactoryBot.create(:user)
# FactoryBot::Syntax::Methods をincludeしていれば
# user = create(:user)
# と省略できる

とかって使うと思います。

RSpec.describe User, type: :model do
  let(:user){ FactoryBot.build :user }

  describe "ユーザー新規登録" do
    context '新規登録できるとき' do
      it '全ての値が正常に入力されていれば登録できる' do
        expect(user).to be_valid
      end
    end

2Like

Comments

  1. 解決しました!!
    ありがとうございます!

    userモデルの正常形単体テストでprofileモデルを使わなければならないと思っていたのが間違いだったようです。
    普通にuserだけbuildしたら通りました。

Your answer might help someone💌