Question

i have a problem with some controller tests. the following two are failing, but i really do not know why. The update and destroy are working.

I am using Rails 4.0 and mongoid.

describe 'POST create' do
context 'with valid attributes' do
  it 'creates a new restaurant' do
    expect {
      post :create, restaurant: FactoryGirl.attributes_for(:random_restaurant)
    }.to change(Restaurant, :count).by(1)
  end

  it 'redirects to the new restaurant' do
    post :create, restaurant: FactoryGirl.attributes_for(:random_restaurant)
    response.should redirect_to Restaurant.last
  end
end

i just added the relation from restaurant to address, updated my factorygirl fixtures.

these are my fixtures:

factory :random_restaurant, parent: :restaurant do |r|
  r.name {Faker::Company.name}
  r.description {Faker::Lorem.sentences}

  after(:build) do |restaurant|
    restaurant.addresses << FactoryGirl.build(:random_address)
  end
end

factory :random_address, parent: :address do |a|
  a.street {Faker::Address.street_address}
  a.zip {Faker::Address.zip_code}
  a.city {Faker::Address.city}
end

the controller post create method looks like this (still default)

# POST /restaurants
# POST /restaurants.json
def create
  @restaurant = Restaurant.new(restaurant_params)

  respond_to do |format|
    if @restaurant.save
      format.html { redirect_to @restaurant, notice: 'Restaurant was successfully created.' }
      format.json { render action: 'show', status: :created, location: @restaurant }
    else
      format.html { render action: 'new' }
      format.json { render json: @restaurant.errors, status: :unprocessable_entity }
    end
  end
end

the errors are:

Failures: 1) RestaurantsController POST create with valid attributes creates a new restaurant
 Failure/Error: expect {
   count should have been changed by 1, but was changed by 0
 # ./spec/controllers/restaurants_controller_spec.rb:39:in `block (4 levels) in <top (required)>'

2) RestaurantsController POST create with valid attributes redirects to the new restaurant
 Failure/Error: response.should redirect_to Restaurant.last
   Expected response to be a <redirect>, but was <200>
 # ./spec/controllers/restaurants_controller_spec.rb:46:in `block (4 levels) in <top (required)>'

Finished in 0.85251 seconds
19 examples, 2 failures

Failed examples:

rspec ./spec/controllers/restaurants_controller_spec.rb:38 # RestaurantsController POST create with valid attributes creates a new restaurant
rspec ./spec/controllers/restaurants_controller_spec.rb:44 # RestaurantsController POST create with valid attributes redirects to the new restaurant

here is an update test which is working:

describe 'PUT update' do
before :each do
  @restaurant = FactoryGirl.create(:random_restaurant)
end

context 'with valid attributes' do
  it 'locates the requested @restaurant' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    assigns(:restaurant).should eq(@restaurant)
  end

  it 'changes @restaurants attributes' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    @restaurant.reload
    @restaurant.name.should eq('A Lodge')
    @restaurant.description.should eq('A Bar')
  end

  it 'redirects to @restaurant' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    response.should redirect_to @restaurant
  end
end

does anyone know, why this fails and how i can solve it? thank you very much

Update: did you mean something like this? this is from test.log

Processing by RestaurantsController#create as HTML
Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
"description"=>["Quae labore quia officia soluta voluptatibus.", "Et error incidunt beatae laborum a libero officiis.", "Non excepturi dolor vel."], 
"thumbnail"=>"some url", "banner"=>"some url"}}
**Unpermitted parameters: thumbnail, banner**

Update 2

these tests are also working:

describe Restaurant do
  it 'has a valid factory' do
    FactoryGirl.create(:random_restaurant).should be_valid
  end

  it 'has an invalid factory' do
    FactoryGirl.build(:random_restaurant_with_invalid_address).should_not be_valid
  end

  it 'is invalid without a name' do
    FactoryGirl.build(:random_restaurant, name: nil).should_not be_valid
  end

  it 'is invalid without a description' do
    FactoryGirl.build(:random_restaurant, description: nil).should_not be_valid
  end

  it 'is invalid without an address' do
    FactoryGirl.build(:random_restaurant_with_invalid_address).should_not be_valid
  end

  it 'creates an address when created' do
    FactoryGirl.create(:random_restaurant)
  end
end

Update 3

My Models:

class Restaurant
  include Mongoid::Document

  has_many :addresses, dependent: :destroy

  validates :name, presence: true
  validates :description, presence: true
  validates :addresses, presence: true

  field :name, type: String
  field :description, type: String
  field :thumbnail, type: String
  field :banner, type: String
end


class Address
  include Mongoid::Document

  belongs_to :restaurant

  validates :street, presence: true
  validates :zip, presence: true
  validates :city, presence: true

  field :street, type: String
  field :zip, type: Integer
  field :city, type: String

  def full_address
    zip_city = [zip, city].join ' '
    [street, zip_city].join ', '
  end
end

Update 4

so, i found this: How is attr_accessible used in Rails 4?

and updated my method. but still not working :(

def restaurant_params
  params.require(:restaurant).permit(:name, :description, :thumbnail, :banner, addresses_attributes: [ :street, :zip, :city ])
end
Was it helpful?

Solution 3

first of all, thank you all for your help. With your ideas i got a solution, i'm now not using factoryGirl. I use, as @PeterGoldstein mentioned, params. I made the mistake, that i used addresses instead of addresses_attributes. I do not know why i have to use it like i had to, but im going to figure it out.

here is now my solution that works for me:

expect {
      post :create, restaurant: { name: 'A-Lodge', description: 'descr',
                                    thumbnail: 'this is url to thumbnail', banner: 'this is url to banner',
                                    addresses_attributes: [ { street: 'street', zip: '8888', city: 'city' } ] }
    }.to change(Restaurant, :count).by(1)

OTHER TIPS

Just put a puts @restaurant.errors.full_messages on the controller, it looks like it's not passing validations

respond_to do |format|
  if @restaurant.save
    format.html { redirect_to @restaurant, notice: 'Restaurant was successfully created.' }
    format.json { render action: 'show', status: :created, location: @restaurant }
  else
    puts @restaurant.errors.full_messages
    format.html { render action: 'new' }
    format.json { render json: @restaurant.errors, status: :unprocessable_entity }
  end
end

no go and run that spec and check the output on the terminal

you can also add this spec to test your factory, that way you can be sure your factory is working right:

it 'creates a valid restaurant from factory girl' do
  rest = FactoryGirl.build :random_restaurant
  rest.should be_valid
end

So the issue is in the use of

FactoryGirl.attributes_for(:random_restaurant)

this isn't adding address attributes, and your restaurant validates the presence of at least on attribute. Take a look at the POSTed attributes from your question:

Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
               "description"=>["Quae labore quia officia soluta voluptatibus.", 
                               "Et error incidunt beatae laborum a libero officiis.", 
                               "Non excepturi dolor vel."], 
               "thumbnail"=>"some url", "banner"=>"some url"}}

There is no address information in here. When you're creating a new restaurant you need at least one address. The POSTed parameters should look like:

Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
               "description"=>["Quae labore quia officia soluta voluptatibus.", 
                               "Et error incidunt beatae laborum a libero officiis.", 
                               "Non excepturi dolor vel."], 
               "thumbnail"=>"some url", "banner"=>"some url",
               "addresses"=>[{"street" => "...", "city => "...", "zip" => "..."}, ...] }}

I suggest you build the attributes manually for the create case. If nothing else, it should help you understand how the controller is parsing the parameters

The unpermitted parameters question is a separate issue, and can be addressed after you've got the address parameters in place.

Is that clear?

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