FactoryGirl определяет атрибут методом вызова на другом factory

Вот пример из документации FactoryGirl :

FactoryGirl.define do
  factory :post do
    name "Post name"
    user
  end
end

В этом примере user вызывает другой factory. То, что я хотел бы сделать, это эффективно вызвать user.id, но установить его как определение атрибута. Здесь урезанный пример:

**models/job.rb**
  ...
  belongs_to :assignee, :class_name => "User"
  belongs_to :user
  ...
  attr_accessible :assignee_id, :user_id
  ...
end


**factories/jobs.rb**
FactoryGirl.define do
  factory :job do
    assignee_id user.id      #what I would like to do, but triggers "undefined method 'id'" error
    user_id user.id          #user_id is an attribute of the model and is the job assignor
 end

Я попытался включить часть документации, которая обсуждает псевдонимы, но не повезло:

FactoryGirl.define do
  factory :user, :aliases => [:assignee] do
  ....

Я чувствую себя (надеюсь?) Я здесь, но всякое понимание прокомментировано. Спасибо.

EDIT: этот код запускает мои спецификации!

**factories/jobs.rb**

FactoryGirl.define do
  factory :job do
    before(:create) do |job|
      user = FactoryGirl.create(:user)
      job.assignee = user
      job.user  = user
    end

  association :assignee, factory: :user
  association :user, factory: :user
  sequence(:user_id) { |n| n }
  sequence(:assignee_id) { |n| n }
  ...
end

И он передает мою спецификацию it { should be_valid }, поэтому кажется, что factory в порядке, хотя я думаю, что у меня есть некоторый рефакторинг в самой спецификации, когда я звоню FactoryGirl.create.

В приведенном выше коде содержатся предложения от mguymon. Спасибо!

ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ

Вернувшись и перечитав обсуждение Hartl по ассоциациям моделей, я смог оставить этот вопрос в покое. То, что у меня было выше, было технически обоснованным, но фактически не передавало атрибуты должным образом, когда я создавал или создавал задания в своей спецификации. Вот что я должен был иметь:

FactoryGirl.define do
  factory :job do
    association :assignee, factory: :user
    user
  end
end

Моя проблема также связана с тем, как я создавал фабрики в своей спецификации, так вот как я должен был это делать (но не... вздох):

    let(:user) { create(:user) }
    before { @job = create(:job, user: @user) }

Кажется, что я не должен явно иметь association :user в моем factory, и мне не нужен блок before сверху.

Как и в стороне, я также узнал, что я могу отлаживать, включив puts @job в оператор expect или вызываю @job.assignee_id, чтобы убедиться, что атрибуты загружаются должным образом. Когда эта конкретная спецификация запускается, оператор puts будет выводиться справа на F или . из спецификации.

Ответ 1

Для последней версии FactoryGirl используйте association для сопоставления с другими моделями ActiveRecord:

factory :job do
  # ...
  association :assignee, factory: :user
end

Это прямо из документов.


Из отправленной вами ошибки указано, что вы пытаетесь получить user.id, но user не является экземпляром ActiveRecord, а прокси-сервером FactoryGirl. Вы не получите эту ошибку, если используете метод association. Если вам нужен прямой доступ к модели, вы должны сначала ее создать вручную. Вы можете сделать это, передав блок в factory:

factory :job do
    assignee_id { FactoryGirl.create(:user).id }
end

Похоже, вы пытаетесь связать одну и ту же модель дважды, для этого вы можете использовать обратный вызов before_create для создания модели пользователя и назначить user и assignee:

factory :job do

  before(:create) do |job|
      user = FactoryGirl.create(:user)
      job.assignee = user
      job.user = user
  end
end