无法在Rspec中建立两个对象之间的关系

时间:2016-04-29 09:57:15

标签: ruby-on-rails ruby mongodb rspec mongoid

我正在写一个名为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"

1 个答案:

答案 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 %>