rails中的外键验证

时间:2015-12-02 01:34:02

标签: ruby-on-rails ruby-on-rails-3 sqlite

我正在尝试设计一个具有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

1 个答案:

答案 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

详细了解上面链接的文档中的覆盖。