我正在尝试设计一个具有1对多关系的数据库,其中1个父项可以有多个子项。数据库似乎工作正常。我正在尝试编写集成测试以检查无效数据并且工作正常,但是当我尝试将有效数据输入数据库时它失败了。它给我一个类似的错误到下面。我在代码中做错了什么,或者我的测试有问题吗?
当我输出child.errors
时.F........#<ActiveModel::Errors:0x007fe0fccb50b8 @base=#<Play id: nil, ad_id: 42, duration: 8, created_at: nil, updated_at: nil>, @messages={:ad=>["can't be blank"]}>
.#<ActiveModel::Errors:0x007fe0fa5756d8 @base=#<Play id: nil, ad_id: 2, duration: 8, created_at: nil, updated_at: nil>, @messages={:ad=>["can't be blank"]}>
整合测试
def setup
Ad.create!(ad_id: 2, device_id: 1, user_id: 1, cost:300.20, title: 'my awesome ad')
Ad.create!(ad_id: 3, device_id: 2, user_id: 3, cost:40, title: 'super')
Ad.create!(ad_id: 1, device_id: 1, user_id: 2, cost:500, title: 'my awesome ad')
Ad.create!(ad_id: 4, device_id: 2, user_id: 2, cost:500, title: 'super')
end
test 'log a valid play' do
post '/plays',
play: {
ad_id: 2,
duration: 8
}
}
assert_equal 201, response.status
end
测试失败
1) Failure:
LogPlayTest#test_log_a_valid_play [/path/log_play_test.rb:18]:
Expected: 201
Actual: 422
儿童迁移
class CreatePlays < ActiveRecord::Migration
def change
create_table :plays do |t|
t.integer :ad_id
t.integer :duration
t.timestamps null: false
end
add_index :plays, :ad_id
end
end
家长迁移
class CreateAds < ActiveRecord::Migration
def change
create_table :ads do |t|
t.integer :ad_id
t.integer :device_id
t.integer :user_id
t.float :cost
t.string :title
t.timestamps null: false
end
add_index :ads, :ad_id
end
end
父模型
class Ad < ActiveRecord::Base
has_many :plays
end
儿童模型
class Play < ActiveRecord::Base
belongs_to :ad
validates :ad, presence: true
end
儿童控制器
def create
play = Play.new(play_params)
if play.save
p play.save
render nothing:true, status: 201, location: play
else
p play.errors #the output is shown above
render json: play.errors, status: 422
end
end
答案 0 :(得分:0)
我说问题出在外键上。当您将测试广告放入数据库时,您将为每个广告提供一个ad_id:
Ad.create!(ad_id: 2...)
我不完全确定你在那里做什么,但是如果那是一个主键,我建议遵循约定并使用Rails自动为你生成的id。例如:
Ad.first.id == 1
与广告相关的游戏会将此主键存储为外键:
Play.first.ad_id == 1
因此:
Play.ad.id == 1
您似乎尝试使用自定义外键而不告诉Rails您正在做什么,这就是找不到父广告的原因。您的两个选择是两个遵循约定或覆盖外键。阅读覆盖覆盖:http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference
如果您选择遵循惯例,只需从广告表中删除ad_id属性,然后使用ID。您可以构建关联以自动设置外键,如下所示:
@ad.plays.new()
如果要覆盖外键,请尝试:
class Play < ActiveRecord::Base
belongs_to :ad, foreign_key: "ad_id"
end
详细了解上面链接的文档中的覆盖。