型号:
class User < ApplicationRecord
has_many :blogs
end
class Blog < ApplicationRecord
belongs_to :user
has_many :posts
validates_presence_of :user_id
# a blog record cannot be created without at least one associated post record
validates :posts, :length => { :minimum => 1 }
end
class Post < ApplicationRecord
belongs_to :blog
belongs_to :user
validates_presence_of :user_id, :blog_id
end
验证是我工厂难以实现的原因。请注意,除非blog
至少有一个post
,否则无法创建post
。另请注意,除非blog_id
有blog
,否则无法创建post
。换句话说:application.rb
和belongs_to
需要构建,它们需要相互关联,并且需要保存它们同时使验证通过。
这是使用Rails 5,所以我确实对# config/application.rb
module MyApp
class Application < Rails::Application
Rails.application.config.active_record.belongs_to_required_by_default = false
end
end
进行了调整,以便FactoryGirl.define do
factory :user do
end
end
FactoryGirl.define do
factory :blog do
user
factory :blog_with_post do
after(:create) do |blog, eval|
the_user_of_blog = blog.user
create(:post, blog: blog, user: the_user_of_blog)
end
end
end
end
FactoryGirl.define do
factory :post do
blog
user
end
end
关联不会对我的工厂造成太大的麻烦:
user
工厂:
blog
我在测试中所做的是创建一个post
记录,然后创建一个user
记录和一个@user = create(:user)
create(:blog_with_post, user: @user)
# => ActiveRecord::RecordInvalid: Validation failed: User can't be blank, Posts is too short (minimum is 1 character)
记录,这两个记录都与同一个{{1}相关联}}。
使用上面的代码:这有效:
after(:build)
尝试
我尝试了factory :blog_with_post do
after(:build) do |blog, eval|
blog_user = blog.user
create(:post, blog: blog, user: blog_user)
end
end
# @user = create(:user)
# create(:blog_with_post, user: @user)
# => ActiveRecord::RecordInvalid: Validation failed: Blog can't be blank
:
before(:create)
我也尝试了factory :blog_with_post do
before(:create) do |blog, eval|
blog_user = blog.user
create(:post, blog: blog, user: blog_user)
end
end
# @user = create(:user)
# create(:blog_with_post, user: @user)
# => ActiveRecord::RecordInvalid: Validation failed: Blog can't be blank
导致同样的错误:
factory :blog_with_post do
after(:build) do |blog, eval|
blog_user = blog.user
build(:post, blog: blog, user: blog_user)
end
end
# @user = create(:user)
# create(:blog_with_post, user: @user)
# => ActiveRecord::RecordInvalid: Validation failed: Posts is too short (minimum is 1 character)
我也试过这个:
FactoryGirl.define do
factory :blog do
user
factory :blog_with_post do
posts {build_list :post, 1, user: THE_USER_OF_THIS_BLOG}
end
end
end
以下内容似乎非常接近,但我不知道如何引用与此博客相关联的用户:
read
答案 0 :(得分:1)
这与我的结果非常接近,并且排除了在没有至少一个blog
的情况下无法创建post
的验证。我无法理解这一点(有工厂,我可以做直线轨道)。但是,我确实知道如何让before(:create)
工作,而不是使用after(:create)
。
归根结底:它归结为一种误解,即协会在被拯救之前如何相互了解,以及协会如何在同一时间自然地保存。
detailed association reference rails文档帮助了我很多,结合使用关联构建记录,保存其中一条记录,然后观察由于belongs_to
而同时保存它们的方式或模型上指定的has_many
关联。
有了这些知识:Post
模型上的这两个验证是导致大多数问题的原因:
validates_presence_of :user_id, :blog_id
此问题(关于此问题中的代码)是,当构建但尚未保存时,blog_id
将不存在>,所以在某些情况下,工厂无效。
因此我们 。相反,我们希望验证 关联 是否存在。换句话说:它只是滥用presence validation的关联。所以将验证更改为:
blog_id
现在剩下要做的就是以正确的方式写工厂:
validates_presence_of :user, :blog
<强>用法强>
factory :blog_with_post do
before(:create) do |blog, eval|
create(:post, blog: blog, user: blog.user)
end
end
由此得出:@user = create(:user)
create(:blog_with_post, user: @user)
和blog
都与user
相关联,post
与user
相关联,所有都是同时保存。