我正在写一个名为Leads controller规范的RSpec。在那里,我正在为铅控制器的创建动作编写测试。现在,我的主管控制器调用Project模型来创建一个对象(Project),该对象还创建Contact对象并将其分配给项目。但是当我尝试测试我的Project模型是否创建一个Contact对象时,测试失败了。我不知道为什么我的联系对象没有被创建:(
我的leads_controller_spec.rb
describe "POST #create" do
it "should create a contact too" do
my_lead = Fabricate(:project, id: Faker::Number.number(10))
expect{
post :create, project: my_lead.attributes
}.to change(Contact, :count).by(1)
end
it "should be equal to last created contact" do
my_lead = Fabricate(:project, id: Faker::Number.number(10))
post :create, project: my_lead.attributes
expect(Project.last.contact).to eq(Contact.last)
end
end
leads_controller.rb
def create
if @lead = Project.add_new_lead(lead_params)
@lead.create_activity :create_new_lead, owner: current_user
puts "My lead in create action: #{@lead.inspect}"
else
respond_to do |format|
format.html { redirect_to :back, :alert => "Email is already Taken"}
end
end
respond_to do |format|
format.html { redirect_to leads_path }
end
end
Project.rb
def add_new_lead(inputs, data = {})
if !Contact.where(email: inputs[:email]).present?
contact = Contact.create(phone: inputs[:phone], email: inputs[:email], fullname: inputs[:fullname])
project = Project.create(name: inputs[:fullname], flat_status: inputs[:flat_status], flat_type: inputs[:flat_type], flat_area: inputs[:area], location: inputs[:locality], address: inputs[:site_address], customer_type: inputs[:customer_type])
project.contact = contact
project.save
project
else
return nil
end
end
contact_fabricator.rb
require 'faker'
Fabricator(:contact) do
email { "email_#{Kernel.rand(1..30000)}@prestotest.com" }
fullname "project#{Kernel.rand(1..30000)}"
address "address#{Kernel.rand(1..30000)}"
end
project_fabricator.rb
require 'faker'
Fabricator(:project) do
contact
end
contact.rb
field :phone, type: String
field :email, type: String
field :fullname, type: String
field :status, type: String, default: "DEFAULT"
field :address, type: String
field :new_address, type: String
field :other_data, type: Hash, default: {}
validates_presence_of :email
validates_uniqueness_of :email, :message => "Email already taken"
答案 0 :(得分:0)
您在规范中使用了错误的工厂。您希望使用Fabricate.attributes_for(:project)
而不是创建记录并获取其属性,因为这将导致任何唯一性验证失败。
require 'rails_helper'
describe ProjectsContoller
describe "POST #create" do
# don't forget to test with invalid input!
context "with invalid attributes" do
let(:attributes) { { foo: 'bar' } }
it "does not create a project" do
expect do
post :create, attributes
end.to_not change(Project, :count)
end
end
context "with valid attributes" do
let(:attributes) { Fabricate.attributes_for(:project) }
it "creates a project" do
expect do
post :create, attributes
end.to change(Project, :count).by(+1)
end
end
end
end
当涉及到控制器的其余部分时,您很可能会使用nested attributes,因为您没有处理联系验证失败的情况。当您使用Contact.create
时,您还在使用Contact.new
。
请注意,这是一个非常高级的主题,您可能希望先学习基础知识,然后再重新访问。
class Project < ActiveRecord::Base
belongs_to :contact
accepts_nested_attributes_for :contact
validates_associated :contact
end
class Contact < ActiveRecord::Base
has_many :projects
end
class ProjectsController < ApplicationController
def new
@project = Project.new
end
def create
@project = Project.new(project_params)
if @project.save
format.html { render :new } # don't redirect!
else
format.html { redirect_to leads_path }
end
end
private
def project_params
params.require(:project).permit(:foo, :bar, contact_attributes: [:email, :name, :stuff, :more_stuff])
end
end
<%= form_for(@project) do |f| %>
<%= f.text_field :foo %>
# These are the attributes for the contact
<%= fields_for :contact do |pf| %>
<%= pf.text_field :email %>
<% end %>
<% end %>