Factory Girl 关联对象实例化[使用设计]

Factory Girl associated object instantiation [using devise]

我有三个模型用户(作者),其中包含设计逻辑:

app/models/user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :questions
  has_many :answers
end

问题:

app/models/question.rb

# Model for Question
class Question < ActiveRecord::Base
  has_many :answers, dependent: :destroy
  belongs_to :author, class_name: 'User', foreign_key: 'user_id'

  validates :title, presence: true, length: { maximum: 100 }
  validates :body, presence: true, length: { minimum: 10 }
  validates :author, presence: true
end

并回答:

app/models/answer.rb

# Model for Answer
class Answer < ActiveRecord::Base
  belongs_to :question
  belongs_to :author, class_name: 'User', foreign_key: 'user_id'

  validates :body, presence: true, length: { minimum: 10 }
  validates :question_id, presence: true
  validates :author, presence: true
end

和他们的工厂:

spec/factories/users.rb

FactoryGirl.define do    
  sequence :email do |n|
    "email-#{n}@example.com"
  end

  sequence :password do |n|
    "testpassword#{n}"
  end

  factory :user, aliases: [:author] do
    email
    # tried sequence generator and fixed password - both have no impact on result
    # password '1234567890'
    # password_confirmation '1234567890'
    password
  end

end

spec/factories/answers.rb

FactoryGirl.define do
  factory :answer do
    body 'Answer Body'
    author
    question
  end

  factory :nil_answer, class: 'Answer' do
    question
    body nil
  end
end

spec/factories/questions.rb

FactoryGirl.define do
  factory :question do
    title 'Question Title'
    body 'Question Body'
    author

    factory :question_with_answers  do
      after(:create) do |question|
        # changing create_list to create has no impact on result
        # create_list(:answer, 2, question: question)
        create(:answer, question: question)
      end
    end
  end
end

测试代码:

spec/features/delete_answer_spec.rb

require 'rails_helper'

feature 'Delete answer', %q{
  By some reason
  As an authenticated user
  I want to delete answer
} do

  given(:question) { create(:question_with_answers) }
  given(:user) { create(:user) }
  given(:ans) { create(:answer) }

  scenario 'Answer author password should not be nil' do
    expect(question.answers.first.author.password).to_not be_nil
    # question.author.password and ans.author.password return not nil
    # I need password to do:
    # visit new_user_session_path
    # fill_in 'Email', with: user.email
    # fill_in 'Password', with: user.password
    # click_on 'Log in'
  end 
end

任何人都可以解释为什么给出以下语句:

given(:question) { create(:question_with_answers) }

创建问题对象:

question.author.password #=> '1234567890'

但是:

question.answers.first.author.password #=> nil

为什么方法 "create" 正确地实例化了问题的作者(设置了字段密码),但是 "create_list" 在 "after" 回调中创建了作者作为答案,没有字段?

rails4.2.5,ruby2.3.0,设计3.5.6,典狱长1.2.6,factory_girls_rails4.6.0(4.5.0)

设计(和大多数身份验证库)加密密码,不允许您访问从数据库检索的模型中的密码。密码可能通过内存中的方法暂时可用 reader,但如果您从数据库中检索记录,则密码将不可用。

如果你这样做:

user = User.new(password: "example")
p user.password

我猜你会看到 "example"

但如果你这样做:

user = User.first
p user.password

我打赌你会看到 nil(假设你的数据库中有用户记录)。

当你查询像question.answers.first.author这样的关联代理时,它会再次进入数据库寻找答案和作者。这意味着您正在使用另一个实例,该实例不再有可用的密码。