验证失败时,相关记录计数仍会更改

时间:2015-05-28 14:42:17

标签: ruby-on-rails rspec tdd

这是一个问题。我有我的模特:

class Collection < ActiveRecord::Base

    has_many    :collection_ownerships
    has_many    :items
    has_many    :users, :through => :collection_ownerships


    validates :title, presence: true, length: { maximum: 25 }
    validates :description, length: { maximum: 100 }
end

class Item < ActiveRecord::Base

    belongs_to :collection
    has_many :item_ownerships, :dependent => :destroy
    accepts_nested_attributes_for :item_ownerships

    validates :name, :presence => true, length: { maximum: 50 }
    validates :collection, :presence => true

end

class ItemOwnership < ActiveRecord::Base

    belongs_to  :item
    belongs_to  :user

    validates :user, :presence => true
    validates :item, :presence => true
end

这是我的控制器代码:

before_filter(:except => :toggle_item_owned_state) do
    @collection = current_user.collections.find(params[:collection_id])
end

def new
    @item = @collection.items.new
    @item_ownership = @item.item_ownerships.build(:owned => true, :user => current_user, :item => @item)
end

def create
    @item = @collection.items.new(item_params)
    @item_ownership = @item.item_ownerships.build(:owned => false, :user => current_user, :item => @item)


    if @item.save
        redirect_to collection_items_path(@collection)
    else
        flash.now[:alert] = "There was a problem saving this item."
        render "new"
    end
end

我有几个控制器测试:

describe 'POST#create' do

            context "with bad data" do
                it "should not create a new record for 'items'" do
                    expect { post :create, :collection_id => batman_collection.id,
                                       :item => { :name => '',
                                                :item_ownership_attributes => { :owned => '1'} }
                            }.to change(Item,:count).by(0) 
                end

                it "should not create new record 'item_ownerships'" do
                    expect { post :create, :collection_id => batman_collection.id,
                   :item => { :name => 'item_name',
                            :item_ownership_attributes => { :owned => '1'} }
                            }.to change(ItemOwnership,:count).by(0) 
                end
            end 
        end

当我运行测试时,第二个测试失败:

  1) ItemsController authenticated user POST#create with bad data should not create new record 'item_ownerships'
     Failure/Error: expect { post :create, :collection_id => batman_collection.id,
       expected #count to have changed by 0, but was changed by 1
     # ./spec/controllers/items_controller_spec.rb:62:in `block (5 levels) in <top (required)>'

最终这也反映在观点中。现在,当我查看数据库时,我看不到创建的记录。我认为这是他发生的事,因为不知何故Count反映了内存中对象的数量,而不是db。

我如何处理这种情况。问题表现在于,当提交表单进行填充时,Item的验证失败,但是,ItemOwnership的多个实例最终会显示在表单上。

由于

2 个答案:

答案 0 :(得分:0)

我发现了问题。我的第二次测试是错误的,因为它实际上正在向服务器提交有效请求,因为该名称&#39;不是空白。

我删除了它,现在测试通过了。

答案 1 :(得分:0)

默认情况下,即使父记录的验证失败,Rails也会保存从嵌套属性创建的记录。这就是Item.count增加的原因。与.count不同的collection#size始终会查询数据库。

您需要做的是在Item上创建一个验证,告诉Rails项目无效,除非父集合有效。

class Item < ActiveRecord::Base

    belongs_to :collection
    has_many :item_ownerships, :dependent => :destroy
    accepts_nested_attributes_for :item_ownerships

    validates :name, :presence => true, length: { maximum: 50 }
    validates :collection, :presence => true
    validates_associated :collection #! 

end

http://guides.rubyonrails.org/active_record_validations.html#validates-associated