首页 > 解决方案 > 尝试更新时基本 CRUD 应用程序出错:ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column:addresses.player_id)

问题描述

我正在用 Rails 构建一个简单的 CRUD 应用程序。到目前为止,我已经完成了 CRUD 的Players. 很快我就会有HighSchoolTeams,ClubTeamsAddresses.

当我尝试更新现有播放器时遇到问题。我收到以下错误:

Started PATCH "/players/3" for ::1 at 2019-12-13 13:43:53 -0800
Processing by PlayersController#update as JS
  Parameters: {"authenticity_token"=>"2fyMlnOWCTn5pt8pyf/W86fRjCO4Af85sbl+3RFDg2OIXAU+T2wU7VxEU3gAxOZPNXvYDcjYpNXMWhImJiEkDQ==", "player"=>{"first_name"=>"Ben", "middle_name"=>"Patrick", "last_name"=>"Stein", "height"=>"", "weight"=>"", "birthday"=>"", "high_school_team"=>"", "club_team"=>"", "email"=>"", "phone_number"=>"", "address_line_one"=>"", "address_line_two"=>"", "city"=>"", "state"=>"", "zip"=>"", "notes"=>""}, "commit"=>"Update Player", "id"=>"3"}
  Player Load (0.2ms)  SELECT "players".* FROM "players" WHERE "players"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/players_controller.rb:30:in `update'
   (0.1ms)  begin transaction
  ↳ app/controllers/players_controller.rb:32:in `update'
  Address Load (0.7ms)  SELECT "addresses".* FROM "addresses" WHERE "addresses"."player_id" = ? LIMIT ?  [["player_id", 3], ["LIMIT", 1]]
  ↳ app/controllers/players_controller.rb:32:in `update'
   (0.1ms)  rollback transaction
  ↳ app/controllers/players_controller.rb:32:in `update'
Completed 500 Internal Server Error in 14ms (ActiveRecord: 1.4ms | Allocations: 5907)

ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: addresses.player_id):

app/controllers/players_controller.rb:32:in `update'

我不确定错误发生了什么。确实没有addresses.player_id专栏。我不打算在那里。我的目的是让玩家Address通过address_id专栏来参考。

在查看我的代码时,我没有发现任何问题。有效负载已成功到达服务器,并且正在成功加载播放器。问题出在@player.update.

玩家控制器.rb

class PlayersController < ApplicationController
  ...

  def edit
    @player = Player.find(params[:id])
  end

  def update
    @player = Player.find(params[:id])

    if @player.update(player_params)
      redirect_to @player
    else
      render 'edit'
    end
  end


  private
    def player_params
      params_for_player = params
        .require(:player)
        .permit(:first_name, :middle_name, :last_name, :height, :weight, :birthday, :high_school_team, :club_team, :email, :phone_number, :address_line_one, :address_line_two, :city, :state, :zip, :notes)
        .except(:address_line_one, :address_line_two, :city, :state, :zip)
      params_for_player["address"] = nil
      params_for_player["high_school_team"] = nil
      params_for_player["club_team"] = nil

      return params_for_player
    end
end

播放器.rb

class Player < ApplicationRecord
  has_one :address
  belongs_to :high_school_team, optional: true
  belongs_to :club_team, optional: true
end

地址.rb

class Address < ApplicationRecord
end

架构.rb

ActiveRecord::Schema.define(version: 2019_12_12_025909) do

  create_table "addresses", force: :cascade do |t|
    t.string "line_one"
    t.string "line_two"
    t.string "city"
    t.string "state"
    t.string "zip"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "club_teams", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "high_school_teams", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "players", force: :cascade do |t|
    t.string "first_name"
    t.string "middle_name"
    t.string "last_name"
    t.decimal "height"
    t.decimal "weight"
    t.date "birthday"
    t.integer "high_school_team_id"
    t.integer "club_team_id"
    t.string "email"
    t.string "phone_number"
    t.integer "address_id"
    t.text "notes"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["address_id"], name: "index_players_on_address_id"
    t.index ["club_team_id"], name: "index_players_on_club_team_id"
    t.index ["high_school_team_id"], name: "index_players_on_high_school_team_id"
  end

  add_foreign_key "players", "addresses"
  add_foreign_key "players", "club_teams"
  add_foreign_key "players", "high_school_teams"
end

标签: ruby-on-rails

解决方案


我打算让玩家通过拥有 address_id 列来引用地址。

class Player
  belongs_to :address
end

class Address
  has_one :player
end

belongs_to使用外键继续模型。但我会说这不是很合乎逻辑。addresses应该有一个player_idbelong_to :player。它是玩家的地址,反之亦然。

如果您想在两个模型之间建立一对一的关系,您需要将belongs_to 添加到一个模型,并将has_one 添加到另一个模型。你怎么知道哪个是哪个?

区别在于您放置外键的位置(它位于表中,用于声明belongs_to 关联的类),但您也应该考虑数据的实际含义。has_one 关系表示某物是你的——也就是说,某物指向你。例如,说供应商拥有客户比说客户拥有供应商更有意义。
- Rails 指南:关联


推荐阅读