Rspec — сообщение — MassAssignmentSecurity::Error

У меня есть несколько моделей: Пользователь и Статья. У пользователя есть_много статей, и статья принадлежит пользователю.

Я пытаюсь написать тест для проверки метода Post (ПРИМЕЧАНИЕ: я использую локали в своем приложении):

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

Но я получаю такую ​​ошибку:

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)>'

Как я могу это исправить?

Мои Фабрики:

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

Мой контроллер:

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

Модель статьи:

# == 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: Приложение здесь: https://github.com/Loremaster/Chirch_app


person ExiRe    schedule 07.09.2012    source источник


Ответы (1)


Без прямого тестирования вашего кода я не могу сказать наверняка, но попробуйте изменить

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

to

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

чтобы вы указали автора статьи, а также не сохраняли article перед вызовом POST. Кроме того, эта строка, вероятно, также должна находиться в вашем блоке describe "for signed-in admin".

Редактировать

Ваши MassAssignmentSecurity::Error исчезнут, если вы измените свой тестовый код так, чтобы вы build использовали :article upfront со всеми необходимыми параметрами, как определено в ваши фабрики:

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 
person Paul Fioravanti    schedule 07.09.2012
comment
Я попробовал ваше решение, и это ничего не изменило. У меня все еще есть моя ошибка. - person ExiRe; 07.09.2012
comment
У вас есть репозиторий Github, которым вы можете поделиться, чтобы люди могли сами протестировать ваш код? - person Paul Fioravanti; 08.09.2012
comment
Да, у меня есть аккаунт на github. Проверьте мое обновление в вопросе, пожалуйста. - person ExiRe; 10.09.2012
comment
Большое спасибо за Вашу помощь! Но у меня все еще проблема с админом. Когда я пытаюсь сделать это: expect do post :create, :locale => :en, :article => @article.attributes.merge(:content => "some" ) end.should change( Article, :count ).by(1), он показывает: Can't mass-assign protected attributes: id, user_id, created_at, updated_at. - person ExiRe; 13.09.2012
comment
Я пробовал так: post :create, :locale => :en, :article => @article и post :create, :locale => :en, :articles => { :content => "some", :title => "text" }, :user_id => @admin.id. Ошибка count should have been changed by 1, but was changed by 0. - person ExiRe; 13.09.2012
comment
Насколько я вижу, если вы измените свой код, чтобы не использовать attributes.merge, вы не получите первого упомянутого вами MassAssignmentSecurity::Error. Что касается вашей второй ошибки, это отдельная проблема: вам нужно найти способ выяснить, что делает controller.sign_in в вашем методе test_sign_in. Я недостаточно знаком с Devise, чтобы помочь вам в этом (возможно, вы могли бы задать его как отдельный вопрос в StackOverflow), но я считаю, что исходная проблема в вашем вопросе была решена. - person Paul Fioravanti; 13.09.2012