我在我的rspec测试中使用factory_girl
。我遇到了在构建中正确设置creator_id
的问题,然后更改为在上一个测试中创建的模型的id。具有来自先前测试的id的模型显然不存在,因此测试失败。我不确定我做错了什么。
我的User
工厂的一部分:
factory :unconfirmed_user, class: User do
sequence(:user_name) { |n| "user#{n}" }
sequence(:email) { |n| "user#{n}@example.com" }
sequence(:authentication_token) { |n| "some random token #{n}" }
sequence(:password) { |n| "password #{n}" }
roles_mask { 2 } # user role
trait :confirmed do
after(:create) do |user|
user.skip_confirmation_notification!
#user.confirm!
user.skip_confirmation!
user.confirmation_token = user.class.confirmation_token
user.confirmation_sent_at = Time.now.utc
user.save(:validate => false)
user.ensure_authentication_token!
end
end
....
factory :confirmed_user, traits: [:confirmed], aliases: [:user, :creator, :updater, :deleter]
....
end
日志记录完成如下:
FactoryGirl.define do
after(:build) { |object|
is_blank = object.respond_to?(:creator) && object.creator.blank? && !object.is_a?(User)
Rails.logger.warn "Built #{is_blank ? '[blank]' : ''} [#{object.object_id}] #{object.inspect}"
}
after(:create) { |object|
is_blank = object.respond_to?(:creator) && object.creator.blank? && !object.is_a?(User)
Rails.logger.warn "Created #{is_blank ? '[blank]' : ''} [#{object.object_id}] #{object.inspect}"
}
....
这是记录的内容。 Project
是一个模型,其属性creator_id
是User
:
Built [82788672] #<Project id: nil, name: "project14", description: "project description 14", urn: "urn:project:14", notes: "note number 14", creator_id: 100, updater_id: nil, deleter_id: nil, deleted_at: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, created_at: nil, updated_at: nil>
Created [blank] [82788672] #<Project id: 11, name: "project14", description: "project description 14", urn: "urn:project:14", notes: "note number 14", creator_id: 99, updater_id: 99, deleter_id: nil, deleted_at: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, created_at: "2014-05-21 04:08:30", updated_at: "2014-05-21 04:08:30">
请注意creator_id
在100
中以build
开头,然后更改为99
中的created
。为什么会这样?
更新
User
模型的相关部分:
require 'role_model'
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable, :confirmable, :lockable, :timeoutable
include RoleModel
attr_accessible :user_name, :email, :password, :password_confirmation, :remember_me,
:roles, :roles_mask, :preferences,
:image
roles :admin, :user, :harvester
model_stamper
# relations
has_many :accessible_projects, through: :permissions, source: :project
has_many :readable_projects, through: :permissions, source: :project, conditions: 'permissions.level = reader'
has_many :writable_projects, through: :permissions, source: :project, conditions: 'permissions.level = writer'
has_many :created_projects, class_name: 'Project', foreign_key: :creator_id, inverse_of: :creator
has_many :updated_projects, class_name: 'Project', foreign_key: :updater_id, inverse_of: :updater
has_many :deleted_projects, class_name: 'Project', foreign_key: :deleter_id, inverse_of: :deleter
# validations
validates :user_name, presence: true, uniqueness: {case_sensitive: false}
validates :email, presence: true, uniqueness: true
validates :roles_mask, presence: true
validates_attachment_content_type :image, content_type: /^image\/(jpg|jpeg|pjpeg|png|x-png|gif)$/, message: 'file type %{value} is not allowed (only jpeg/png/gif images)'
before_validation :ensure_user_role
def projects
(self.created_projects + self.accessible_projects).uniq
end
private
def ensure_user_role
self.roles << :user if roles_mask.blank?
end
答案 0 :(得分:1)
我终于弄明白了。拼图的关键部分是&#34;在发生异常时不调用过滤器&#34; (在Rails APIDock页面的评论中找到,目前无法找到确切的链接。)
userstamp
gem I am using sets the user on a before_filter, then removes the user in an after_filter。问题是如果有异常,则after_filter将不会运行。这在正常操作中无关紧要 - 用户仍将被设置,但在其他用户登录时将被覆盖。这可能会导致其他我不知道的安全问题。
测试中的问题是,因为模型是在通常的rails应用程序周期之外创建并插入到db中的,所以如果发生异常则由userstamp gem存储的id在测试之间保持(因为它们被存储)在线程中)。这意味着标记了错误的用户标识(这就是在构建和创建之间id发生变化的原因)。
总而言之,rails before_filter和after_filter的工作方式不同,导致混乱。测试会导致gem中的活动不同,在这种情况下会导致状态保持在测试之间。
我似乎已经通过在处理错误的方法的末尾添加调用来重置/清除存储的用户来解决它(在我的情况下,在application_controller.rb
中)。这确保了在操作结束时,就好像after_filter一样,所以userstamp
gem的状态就像它期望的那样。我可能需要使用不同的(并且更积极维护的)gem或者gem的分支:/
呼。