[英]rspec + factorygirl : stack level too deep
I have an Account and a User models. 我有一个帐户和一个用户模型。 With Account: has_one :owner, class_name: 'User'
and has_many :users
. 使用Account: has_one :owner, class_name: 'User'
和has_many :users
。
My first spec is failing : 我的第一个规格失败了:
1) User has a valid factory
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /usr/local/rvm/gems/ruby-2.1.1/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:222
I am looking for a loop, but I don't see it ! 我正在寻找一个循环,但看不到! The user factory calls the account factory which calls the owner factory... anything wrong with that ? 用户工厂呼叫帐户工厂,而帐户工厂呼叫所有者工厂...这有什么问题吗?
## /spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, :type => :model do
it "has a valid factory" do
expect(FactoryGirl.create(:user)).to be_valid
end
end
My 2 factories : 我的两个工厂:
## /spec/factories/accounts.rb
require 'faker'
FactoryGirl.define do
factory :account do
name { Faker::Company.name }
subdomain { Faker::Internet.domain_word }
association :owner, factory: :owner, strategy: :build
end
end
## /spec/factories/users.rb
require 'faker'
FactoryGirl.define do
factory :user do
firstname { Faker::Name.first_name }
lastname { Faker::Name.last_name }
email { Faker::Internet.email }
password { Faker::Internet.password(6) }
association :account, factory: :account, strategy: :build
role {"employee"}
end
factory :owner, class: User do
firstname { Faker::Name.first_name }
lastname { Faker::Name.last_name }
email { Faker::Internet.email }
password { Faker::Internet.password(6) }
role {"owner"}
end
end
EDIT, adding the 2 models : 编辑,添加2个模型:
class User < ActiveRecord::Base
include ActiveModel::Dirty
include PublicActivity::Common
##
# user ROLES can be owner, manager or employee
ROLES =%w[owner manager employee]
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
acts_as_messageable
acts_as_tenant :account
accepts_nested_attributes_for :account
######################################################################
# Relations #
######################################################################
belongs_to :team
has_many :posts
has_many :shifts
######################################################################
# Validations #
######################################################################
validates :lastname, presence: true, allow_nil: false
validates :firstname, presence: true, allow_nil: false
validates :email, presence: true, allow_nil: false
validates_uniqueness_of :email, scope: :account_id
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
validates :password,
presence: true,
length: { :in => 2..20 },
:if => :password_required?, unless: :skip_password_validation
validates :role, presence: true
######################################################################
# Callbacks #
######################################################################
before_save :delete_avatar, if: -> { remove_avatar == '1' && !avatar_updated_at_changed? }
before_create :default_values
######################################################################
# Scope #
######################################################################
scope :active, -> (active) { where active: active }
scope :active_without_owner, -> { active(true).where.not(role: 'owner') }
scope :active_grouped, -> { where(active: true).group("id","team_id") }
scope :team, -> (team_id) { where team_id: team_id }
scope :starts_with, -> (lastname) { where("lastname like ?", "#{lastname}%") }
scope :sort_lastname, -> { order("users.lastname ASC") }
scope :account_id, -> { where account_id: account_id }
attr_accessor :is_manager, :last_current_user, :skip_password_validation
def activebydefault
self.active = true if self.active.nil?
end
private
def default_values
self.active ||= 'true'
self.save
true
end
end
class Account < ActiveRecord::Base
RESTRICTED_SUBDOMAINS = %w(www)
######################################################################
# Relations #
######################################################################
has_one :owner, class_name: 'User'
has_many :users
has_many :teams
accepts_nested_attributes_for :owner, :teams
######################################################################
# Validations #
######################################################################
validates :owner, presence: true
validates :name, presence: true
validates :subdomain, presence: true,
uniqueness: { case_sensitive: false, message: 'already used' },
format: { with: /\A[\w\-]+\Z/i, message: 'contains invalid characters' },
exclusion: { in: RESTRICTED_SUBDOMAINS, message: 'restricted' }
validates :time_zone, allow_nil: true,
inclusion: {
in: ActiveSupport::TimeZone.zones_map(&:name).keys
}
######################################################################
# Callbacks #
######################################################################
before_validation :downcase_subdomain
after_create :add_owner_to_team, :default_values, :send_notification
private
def downcase_subdomain
self.subdomain = subdomain.try(:downcase)
end
def default_values
self.publish_to_wall_new_employee = true
self.publish_to_wall_published_schedule = true
self.publish_to_wall_modified_schedule = true
self.publish_to_wall_new_document = true
self.save
true
end
end
EDIT 2 : added the tail 编辑2:添加了尾巴
ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
(0.2ms) BEGIN
(0.3ms) SAVEPOINT active_record_1
User Exists (1.0ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" IS NULL) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" IS NULL) LIMIT 1
Account Exists (0.5ms) SELECT 1 AS one FROM "accounts" WHERE LOWER("accounts"."subdomain") = LOWER('jean') LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'thomas.benoit@bourgeois.net' AND "users"."account_id" IS NULL) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'thomas.benoit@bourgeois.net' AND "users"."account_id" IS NULL) LIMIT 1
SQL (0.4ms) INSERT INTO "accounts" ("created_at", "name", "subdomain", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", "2015-02-02 19:58:20.000241"], ["name", "Pierre EURL"], ["subdomain", "jean"], ["updated_at", "2015-02-02 19:58:20.000241"]]
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'lola.francois@legrand.com' AND "users"."account_id" = 131) LIMIT 1
and goes and goes... 走走走走...
I suppose it happens just because of before_create
callback: 我想它的发生仅仅是因为before_create
回调:
User
model: User
模型:
def default_values
self.active ||= 'true'
self.save
true
end
try replace to: 尝试替换为:
def default_values
self.active ||= 'true'
end
you don't need call save
manually (because it's looping your callback) 您不需要手动save
呼叫(因为这会循环您的回调)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.