Rspec =と<<の使い方

articleに対して、authorとtagが関連付けられています。 article.rb

class Article < ApplicationRecord
  belongs_to :author

  has_many :tags, through: :article_tags
  has_many :article_tags
.
.

author.rb

class Author < Taxonomy
  has_many :articles
end

tag.rb

class Tag < Taxonomy
  has_many :articles, through: :article_tags
end


  trait :with_author do
    transient do
      sequence(:author_name) { |n| "test_author_name_#{n}" }
      sequence(:tag_slug) { |n| "test_tag_slug_#{n}" }
    end

    after(:build) do |article, evaluator|
      article.author = build(:tag, name: evaluator.author_name, slug: evaluator.tag_slug)
    end
  end
  trait :with_tag do
    transient do
      sequence(:tag_name) { |n| "test_tag_name_#{n}" }
      sequence(:tag_slug) { |n| "test_tag_slug_#{n}" }
    end

    after(:build) do |article, evaluator|
      article.tags << build(:tag, name: evaluator.tag_name, slug: evaluator.tag_slug)
    end
  end

authorの時は=で書くのに対し、

article.author = build(:tag, name: evaluator.author_name, slug: evaluator.tag_slug)

tagの時は<<で書く理由がわかりませんでした。

article.tags << build(:tag, name: evaluator.tag_name, slug: evaluator.tag_slug)



binding.pryで確認

 [1] pry(#<FactoryBot::SyntaxRunner>)> article.tags
=> []

article.tagsと入力すると、配列になっていることが分かります。

Rails guideのhas_many関連付の詳細より、has_manyで追加されるメソッドに<<がありました。これにより、生成したインスタンスをarticle.tags配列の末尾に挿入してくれます。

article.tags

pry(main)> author.articles
[46] pry(main)> article.tags
=> [#<Tag:0x00007fee1f1b0688
  id: 1,
  type: "Tag",
  name: "saa",
  slug: "saae",
  description: nil,
  created_at: Thu, 03 Jun 2021 21:20:32 JST +09:00,
  updated_at: Thu, 03 Jun 2021 21:20:32 JST +09:00>,
 #<Tag:0x00007fee1f1b0408
  id: 5,
  type: "Tag",
  name: "アニメ 推理",
  slug: "ssss",
  description: nil,
  created_at: Sat, 05 Jun 2021 07:17:32 JST +09:00,
  updated_at: Sat, 05 Jun 2021 07:17:32 JST +09:00>]

author.rbでhas_many: tagsとしているので、配列になっている。

article.author

[45] pry(main)> article.author
=> #<Author:0x00007fee168225b0
 id: 3,
 type: "Author",
 name: "青山剛昌",
 slug: "sulug",
 description: "名探偵コナンの作者",
 created_at: Sat, 05 Jun 2021 07:05:23 JST +09:00,
 updated_at: Sat, 05 Jun 2021 07:05:23 JST +09:00>
[46] pry(main)> 

article.rbでbelongs_to :authorとなっているので配列ではない。

一般的に「=」は代入なので、左辺を全て右辺の値で上書きします。 author.articlesというのは配列ですよね(正確にいうとActiveRecord::Relation)。今回のケースではarticle.tagsを右辺で上書きするのではなく、配列に追加します。



binding.pryで中身を見てみよう!

  trait :with_author do
    transient do
      sequence(:author_name) { |n| "test_author_name_#{n}" }
      sequence(:tag_slug) { |n| "test_tag_slug_#{n}" }
    end

    after(:build) do |article, evaluator|
      article.author = build(:tag, name: evaluator.author_name, slug: evaluator.tag_slug)
    end
  end
1] pry(#<FactoryBot::SyntaxRunner>)> build(:author, name: evaluator.author_name, slug: evaluator.tag_slug) 
=> #<Author:0x00007fc258193ad0 id: nil, type: "Author", name: "伊藤", slug: "test_author_slug_1", description: nil, created_at: nil, updated_at: nil>

slugはtransientで定義しているtest_author_slug_1になっているが、nameはletで記載している”伊藤”になっています。



参考URL

railsguides.jp