Question

http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html# going off of this tutorial currently. i am adding on to another project that i started from the rails apps tutorial.

as i go to create my models specs contact_spec.rb

require 'spec_helper'

describe Contact do 
it "has a valid factory" do
    FactoryGirl.create(:contact).should be_valid
end
it "is invalid without a firstname"
it "is invalid without a lastname"
it "returns a contact's full name as a string"  
end

factories/contacts.rb

require 'faker'

FactoryGirl.define do
    factory :contact do |f|
    f.firstname { Faker::Name.first_name }
    f.lastname { Faker::Name.last_name }
    end
end

i run rspec and recieve this error:

    1) Contact has a valid factory
    Failure/Error: FactoryGirl.create(:contact).should be_valid
    NoMethodError:
    undefined method `firstname=' for #<Contact name: nil, email: nil, content: nil>
    # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'
    Finished in 0.22028 seconds
    4 examples, 1 failure, 3 pending

here is my contact model

 class Contact < ActiveRecord::Base
  has_no_table

  column :name, :string
  column :email, :string
  column :content, :string

  validates_presence_of :name
  validates_presence_of :email
  validates_presence_of :content
  validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
  validates_length_of :content, :maximum => 500

  def update_spreadsheet
    connection = GoogleDrive.login(ENV["GMAIL_USERNAME"], ENV["GMAIL_PASSWORD"])
    ss = connection.spreadsheet_by_title('Learn-Rails-Example')
     if ss.nil?
      ss = connection.create_spreadsheet('Learn-Rails-Example')
    end
    ws = ss.worksheets[0]
    last_row = 1 + ws.num_rows
    ws[last_row, 1] = Time.new
    ws[last_row, 2] = self.name
    ws[last_row, 3] = self.email
    ws[last_row, 4] = self.content
    ws.save
  end

end

and my contactS_controller

class ContactsController < ApplicationController

  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(secure_params[:contact])
    if @contact.valid?
      @contact.update_spreadsheet
      UserMailer.contact_email(@contact).deliver
      flash[:notice] = "Message sent from #{@contact.name}."
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def secure_params
    params.require(:contact).permit(:name, :email, :content)
  end

end

i tried changing :name to be :firstname, and :lastname and ended up getting this new error

1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::RecordInvalid:
       Validation failed: Email can't be blank, Email is invalid, Content can't be blank
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.22596 seconds
4 examples, 1 failure, 3 pending

Failed examples:

rspec ./spec/models/contact_spec.rb:4 # Contact has a valid factory

my guess is that i havent defined something right when i reference to :contact.

edit adding the Faker::Internet.email attr brought up a new error

 1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::RecordInvalid:
       Validation failed: Content can't be blank
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

so i comment out validates_presence_of :content, column :content, and validates_length_of :content and get this

 1) Contact has a valid factory
     Failure/Error: FactoryGirl.create(:contact).should be_valid
     ActiveRecord::Tableless::NoDatabase:
       Can't #create_record a Tableless object
     # ./spec/models/contact_spec.rb:5:in `block (2 levels) in <top (required)>'

so it seems that things are working as i apply them or take away, i apparently have lots of conflicts between the code i wrote following one tutorial and adding this method using rspec factory_girl and faker

edit 2 so after the addition of the email and content attr, i continued on with filling out the remaining specs for "invalid without first/lastname":

    describe Contact do 
            it "has a valid factory" do
        FactoryGirl.build(:contact).should be_valid
        end
        it "is invalid without a firstname" do 
            FactoryGirl.build(:contact, lastname: nil).should_not be_valid 
        end

         it "is invalid without a lastname" do 
            FactoryGirl.build(:contact, lastname: nil).should_not be_valid 
        end

        it "returns a contact's full name as a string"  
    end

and my tests passed with no errors:

  is invalid without a lastname
  has a valid factory
  is invalid without a firstname
  returns a contact's full name as a string (PENDING: Not yet implemented)

Pending:
  Contact returns a contact's full name as a string
    # Not yet implemented
    # ./spec/models/contact_spec.rb:15

Finished in 0.22146 seconds
4 examples, 0 failures, 1 pending

thank you sonnyhe2002 for getting me through this! much appreciated!

Was it helpful?

Solution

You need to add an email attr to your factory

FactoryGirl.define do
  factory :contact do |f|
    f.firstname { Faker::Name.first_name }
    f.lastname { Faker::Name.last_name }
    f.email { Faker::Internet.email }
    f.content 'This is content'
  end
end

Since you are using has_no_table, I think factory cannot save it into the database.

You should use 'build' instead of 'create'

FactoryGirl.build(:contact).should be_valid

OTHER TIPS

Are you sure you have a firstname column in your database? Make sure db/schema.rb has a firstname column for the contacts table, and make sure you've run rake db:test:prepare

The errors given are quite self-descriptive: you have some validators on your email and content attributes but you are not setting these attributes in your Contact Factory to make valid your model.

Edit: please add this to your contact factory:

f.email 'email@example.com'
f.content 'a content'

In your model:

validates_presence_of :name
validates_presence_of :email
validates_presence_of :content
validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
validates_length_of :content, :maximum => 500

so, while making a FactoryGirl user you need to consider the above facts. You only handled the presence of email and name, but also need to handle the presence of content which needs to be less than 500 characters in length.

FactoryGirl is now replaced by FactoryBot. FactoryGirl is deprecated.

FactoryBot version 5 onwards only supports dynamic attributes while creating the factory.

So the solution is:-

FactoryBot.define do factory :user do name { "Ron" } email { "ron@gmail.com" } password { "ronY123" } password_confirmation { "ronY123" } end end

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top