2

I have few models: User and Article. User has_many articles and Article belongs to user.

I try to write test to check Post method (NOTE: i use locales in my application):

require 'spec_helper'

describe ArticlesController do
  render_views

  before(:each) do
    @admin = FactoryGirl.create( :admin )
    @user  = FactoryGirl.create( :user )
  end

  describe "POST 'create'" do
    before(:each){ @article = FactoryGirl.create(:article) }

    describe "for signed-in admin" do
      before(:each){ test_sign_in( @admin ) }

      it "should create article" do
        expect do
          post :create, :locale => :en, :article => @article.attributes.merge( :content => "some" )
        end.should change( Article, :count ).by(1)
      end
    end
  end
end

But i get such error:

1) ArticlesController POST 'create' for signed-in admin should create article
     ActiveModel::MassAssignmentSecurity::Error:
       Can't mass-assign protected attributes: id, user_id, created_at, updated_at
     Failure/Error: post :create, :locale => :en, :article => @article.attributes.merge( :content => "some" )
     # ./app/controllers/articles_controller.rb:15:in `create'
     # ./spec/controllers/articles_controller_spec.rb:106:in `block (5 levels) in <top (required)>'
     # ./spec/controllers/articles_controller_spec.rb:105:in `block (4 levels) in <top (required)>'

How can i fix that?

My Factories:

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "email#{n}@factory.com" }
    password  'qwerty'

    factory :admin do
      admin true
    end
  end

  factory :article do
    content 'text is here'
    user
  end
end

My controller:

class ArticlesController < ApplicationController
  before_filter do
    redirect_to :root unless current_user && current_user.admin?
  end

  def create
    @article = Article.new( params[:article] )

    if @article.save
      redirect_to articles_path
      flash[:success] = "It has been created!"
    else
      render 'new'                                                                       
    end
  end
end

Article model:

# == Schema Information
#
# Table name: articles
#
#  id         :integer          not null, primary key
#  user_id    :integer
#  content    :text
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class Article < ActiveRecord::Base
  belongs_to :user

  attr_accessible :content

  validates :content,
              :presence => { :message => :presense_message },
              :length   => {
                             :maximum => 50000,
                             :message => :max_lenght_message
                           }
end

UPD: Application is here: https://github.com/Loremaster/Chirch_app

Paul Fioravanti
  • 16,423
  • 7
  • 71
  • 122
ExiRe
  • 4,727
  • 7
  • 47
  • 92

1 Answers1

1

Without testing your code directly I can't say for sure, but try changing

before(:each){ @article = FactoryGirl.create(:article) } 

to

before(:each){ @article = FactoryGirl.build(:article, :user => @admin) } 

so that you are giving the article an author as well as not saving the article before you make the call to POST. Also, this line should probably also go within your describe "for signed-in admin" block.

Edit

Your MassAssignmentSecurity::Errors will go away if you change your test code so that you build your :article upfront with all the necessary parameters as defined in your factories:

spec/controllers/articles_controllers.spec

describe "POST 'create'" do
  before(:each) do
    @article = FactoryGirl.build(:article, :user => @admin, :content => "some")
  end

describe "for non-signed users" do
  it "should deny access" do
    post :create, :locale => :en, :article => @article
    response.should redirect_to( root_path )
  end

  it "should not create article" do
    expect do
      post :create, :locale => :en, :article => @article
    end.should_not change( Article, :count )
  end
end

describe "for signed-in users" do
  before(:each){ test_sign_in( @user ) }

  it "should deny access" do
    post :create, :locale => :en, :article => @article
    response.should redirect_to( root_path )
  end

  it "should not create article" do
    expect do
      post :create, :locale => :en, :article => @article
    end.should_not change( Article, :count )
  end
end 
Paul Fioravanti
  • 16,423
  • 7
  • 71
  • 122
  • I tried your solution and this changed nothing. I still have my error. – ExiRe Sep 07 '12 at 18:52
  • Got a Github repo you can share so people can test your code for themselves? – Paul Fioravanti Sep 08 '12 at 05:45
  • Yes, i have github account. Check my update in question, please. – ExiRe Sep 10 '12 at 17:14
  • 1
    Thank you very much for your help! But i still have problem with admin. When i try that: `expect do post :create, :locale => :en, :article => @article.attributes.merge(:content => "some" ) end.should change( Article, :count ).by(1)` it shows: `Can't mass-assign protected attributes: id, user_id, created_at, updated_at`. – ExiRe Sep 12 '12 at 21:04
  • I tried that: `post :create, :locale => :en, :article => @article` and `post :create, :locale => :en, :articles => { :content => "some", :title => "text" }, :user_id => @admin.id`. Error is `count should have been changed by 1, but was changed by 0`. – ExiRe Sep 12 '12 at 21:08
  • As far as I can see, if you change your code to not use `attributes.merge`, you won't get the first `MassAssignmentSecurity::Error` you mentioned. As for your second error, that's a separate problem: you will need to find some way to figure out what `controller.sign_in` in your `test_sign_in` method is doing. I'm not familiar enough with Devise to help you there (perhaps you could pose it as a separate question on StackOverflow), but I believe the original problem in your question has been solved. – Paul Fioravanti Sep 12 '12 at 22:07