在一个模型中提供两个多态关联



>我有以下模型:GameHighSchoolTeamClubTeam。我希望Game两个有一个team_one和一个team_two字段,每个字段都指一个HighSchoolTeam或一个ClubTeam

HighSchoolTeamClubTeam我有has_many :games, as: :teamable.在Game我想做类似的事情...

class Game < ApplicationRecord
belongs_to :team_one, polymorphic: true, class_name: "Teamable"
belongs_to :team_two, polymorphic: true, class_name: "Teamable"
end

。但是class_name: "Teamable部分似乎不起作用。


编辑:

模式.rb

ActiveRecord::Schema.define(version: 2019_12_24_011346) do
...
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 "fields", 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 "games", force: :cascade do |t|
t.bigint "tournament_id", null: false
t.string "team_one_type", null: false
t.bigint "team_one_id", null: false
t.string "team_two_type", null: false
t.bigint "team_two_id", null: false
t.bigint "field_id", null: false
t.date "date"
t.datetime "start_time"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["field_id"], name: "index_games_on_field_id"
t.index ["team_one_type", "team_one_id"], name: "index_games_on_team_one_type_and_team_one_id"
t.index ["team_two_type", "team_two_id"], name: "index_games_on_team_two_type_and_team_two_id"
t.index ["tournament_id"], name: "index_games_on_tournament_id"
end
create_table "high_school_teams", force: :cascade do |t|
t.string "school_name"
t.string "team_name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "tournaments", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "games", "fields"
add_foreign_key "games", "tournaments"
end

游戏.rb

class Game < ApplicationRecord
belongs_to :tournament
belongs_to :team_one, polymorphic: true
belongs_to :team_two, polymorphic: true
belongs_to :field, optional: true
end

high_school_team.rb

class HighSchoolTeam < ApplicationRecord
has_many :players
has_many :games, as: :teamable, dependent: :destroy
def name
self.school_name
end
end

club_team.rb

class ClubTeam < ApplicationRecord
has_many :players
has_many :games, as: :teamable, dependent: :destroy
end

控制台输出

code/scout-db [master●] » rails c --sandbox
Running via Spring preloader in process 48525
Loading development environment in sandbox (Rails 6.0.1)
Any modifications you make will be rolled back on exit
WARNING: This version of ruby is included in macOS for compatibility with legacy software.
In future versions of macOS the ruby runtime will not be available by
default, and may require you to install an additional package.
irb(main):001:0> game = Game.new({ team_one_id: "high-school-team-2", team_one_type: "HighSchoolTeam", team_two_id: "club-team-2", team_two_type: "ClubTeam" })
(0.2ms)  BEGIN
=> #<Game id: nil, tournament_id: nil, team_one_type: "HighSchoolTeam", team_one_id: 0, team_two_type: "ClubTeam", team_two_id: 0, field_id: nil, date: nil, start_time: nil, created_at: nil, updated_at: nil>
irb(main):002:0> game.team_one_id
=> 0
irb(main):003:0> game.save
(0.3ms)  SAVEPOINT active_record_1
HighSchoolTeam Load (0.4ms)  SELECT "high_school_teams".* FROM "high_school_teams" WHERE "high_school_teams"."id" = $1 LIMIT $2  [["id", 0], ["LIMIT", 1]]
ClubTeam Load (0.3ms)  SELECT "club_teams".* FROM "club_teams" WHERE "club_teams"."id" = $1 LIMIT $2  [["id", 0], ["LIMIT", 1]]
(0.4ms)  ROLLBACK TO SAVEPOINT active_record_1
=> false
irb(main):004:0> game.errors.full_messages.inspect
=> "["Tournament must exist", "Team one must exist", "Team two must exist"]"

(2, Syosset, Braves, 2019-12-31 01:07:41.367913, 2019-12-31 01:07:41.367913)存在于high_school_teams表中,(2, Foobars, 2019-12-31 01:07:52.697821, 2019-12-31 01:07:52.697821)存在于club_teams表中。

当然class_name: "Teamable"不起作用,因为多态关联的全部要点是关联的类(更重要的是目标表(是动态的。它也不需要。

多态关联使用单独的association_name_type字符串列,其中包含与其关联的类名。

给定以下数据:

| id | team_one_id | team_one_type # ...
----------------------------------
1    |  1          | "HighSchoolTeam"
2    |  2          | "ClubTeam"
3    |  3          | "HighSchoolTeam"

当你这样做时Game.find(1).team_oneRails知道使用HighSchoolTeam类并加入high_school_teams表。但是它需要先拉出行才能建立连接,当然,您的数据库对关系一无所知,也不会维护引用完整性。

所以你所需要的只是:

class Game < ApplicationRecord
belongs_to :team_one, polymorphic: true
belongs_to :team_two, polymorphic: true
end

并确保games表上有team_one_typeteam_two_type字符串列。

class_name应该与数据库中的类名匹配。

最新更新