Factory Girl / Rspec - "Trait Not Registered" 错误

10
跟随Ben Walker(惊人的)使用Rails构建Instagram,特别是BDD版本。教程使用了FactoryGirl。我在许多测试中遇到以下错误:
Failure/Error: post = create( :post, user_id = user.id )<br>
ArgumentError:<br>
Trait not registered: 1

我无法让Ben使用我的repo的克隆重现这个bug,并且在Stack Overflow“trait not registered”问题中也没有找到任何内容。
这是我第一个在SO上的问题,如果我在这方面做错了什么,请告诉我。提前感谢您的帮助!
代码选择:

spec/factories.rb

FactoryGirl.define do
  factory :post do
    caption "nofilter"
    image Rack::Test::UploadedFile.new(Rails.root + 'spec/files/images/coffee.jpg', 'image/jpg')
    user_id 1
  end
  factory :user do
    email 'fancyfrank@gmail.com'
    user_name 'Arnie'
    password 'illbeback'
    id 1
  end
end

spec/features/viewing_posts_spec.rb

require 'spec_helper'

feature 'viewing individual posts' do
  background do
    user = create :user
    post = create( :post, user_id = user.id )

    sign_in_with user
  end

  scenario 'can click and view a post' do
    post = create(:post)

    visit '/'
    find(:xpath, "//a[contains(@href,'posts/2')]").click
    expect(page.current_path).to eq(post_path(post))
  end
end

app/models/post.rb

class Post < ActiveRecord::Base
  belongs_to :user

  validates :user_id, presence: true

   validates :image, presence: true

  has_attached_file :image, styles: { :medium => "640x" }

  validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end

app/models/user.rb

class User < ActiveRecord::Base
  validates :user_name, presence: true, length: { minimum: 4, maximum: 16 }
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :posts, dependent: :destroy
end

app/controllers/posts_controller.rb

class PostsController < ApplicationController
  before_action :authenticate_user!

  def index
    @posts = Post.all
  end

  def new
    @post = current_user.posts.build
  end

  def create
    @post = current_user.posts.build(post_params)
    if @post.save
      flash[:success] = 'Your post has been created.'
      redirect_to posts_path
    else
      flash[:alert] = 'Halt, you fiend! You need an image to post here!'
      render :new
    end
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
    @post = Post.find(params[:id])
    if @post.update(post_params)
      flash[:success] = 'Post updated hombre.'
      redirect_to root_path
    else
      flash[:alert] = 'Something is wrong with your form!'
      redirect_to root_path
    end
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    flash[:success] = 'Problem solved!  Post deleted.'
    redirect_to root_path
  end

  private

  def post_params
    params.require(:post).permit(:caption, :image)
  end
end

完整错误信息(众多错误之一)

viewing individual posts can click and view a post
     Failure/Error: post = create( :post, user_id = user.id )
     ArgumentError:
       Trait not registered: 1
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/registry.rb:24:in `find'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/decorator.rb:10:in `method_missing'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl.rb:98:in `trait_by_name'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:113:in `trait_by_name'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:109:in `block in additional_traits'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:109:in `map'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:109:in `additional_traits'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:135:in `block in aggregate_from_traits_and_self'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:128:in `tap'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:128:in `aggregate_from_traits_and_self'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition.rb:33:in `to_create'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/definition_hierarchy.rb:16:in `build_from_definition'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/factory.rb:124:in `build_hierarchy'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/factory.rb:87:in `compile'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/factory.rb:32:in `run'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/factory_runner.rb:23:in `block in run'
     # /var/lib/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/notifications.rb:166:in `instrument'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/factory_runner.rb:22:in `run'
     # /var/lib/gems/2.1.0/gems/factory_girl-4.5.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
     # ./spec/features/viewing_posts_spec.rb:6:in `block (2 levels) in <top (required)>'
2个回答

5

修改您的工厂以使用关联

FactoryGirl.define do
  factory :post do
    caption "nofilter"
    image Rack::Test::UploadedFile.new(Rails.root + 'spec/files/images/coffee.jpg', 'image/jpg')
    association user
  end
  factory :user do
    email 'fancyfrank@gmail.com'
    user_name 'Arnie'
    password 'illbeback'
    sequence(:id) { |id| id }
  end
end

然后,像这样创建用户和发布文章:
user = create :user
post = create(:post, user: user)

这应该可以工作。

了解更多关于factory_girl关联的内容。


2
谢谢,你帮我解决了问题。奇怪的是,按照你的方法仍然出现错误('Failure/Error: post = create( :post, user: user ) NoMethodError: undefined method `to_sym' for #FactoryGirl::Declaration::Implicit:0x000000066209e8'),但是去掉关联(因为关联与工厂名称相同,根据你给我的链接)解决了问题。我需要进一步深入研究这个问题,因为虽然它可以工作,但我不知道为什么。但是还是非常感谢你。 - Parker Harris Emerson
是的没错。如果关联名称与工厂名称相同,则无需使用“association”关键字。但是,我认为那仍然可以工作,并在那里使用它来向您展示这是关联。但是,在发布之前我没有测试过它。很高兴你发现了 :) +1 - K M Rakibul Islam

2

我也遇到了这个完全一样的错误信息,原因是我的规范文件中有以下代码行。

# .spec file

let!(:user) { create(:user) }
let!(:board) { create(:board, 1, user_id: user.id) }
let!(:categories) { create_list(:category, 5, board_id: board.id) }

在我的应用程序中,用户有许多板块,每个板块有许多类别。在我的规范的这一部分中,我试图创建一个用户、一个板块,并通过id属性将其链接到该用户,以及一个包含5个类别的列表,每个类别都通过category上的id属性链接到那个板块。
问题在于,我将创建categoriescreate_list函数的参数复制并粘贴为创建一个板块的create函数的参数。 create函数期望第二个参数是属性覆盖,而create_list函数期望一个整数,表示要用多少个对象填充列表。
错误显示是因为在create函数中的第二个参数1,原本用于单个category,现在却被解释成“属性覆盖”,因为这正是create函数期望的第二个参数。通过将create中的第二个参数1移除,错误消失了,因为提供了正确的参数。
干杯!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接