Rails自我引用has_many通过:没有添加正确的记录

时间:2016-11-08 21:54:20

标签: ruby-on-rails ruby postgresql activerecord

这一整天都在破坏我的大脑。我为pool_tournament_match创建了一个has_many关系,所以每个匹配都可以有很多其他匹配。我创建了一个名为的表 pool_tournament_match_relationships

create_table :pool_tournament_match_relationships do |t| t.belongs_to :parent, class_name: 'PoolTournamentMatch', index: true t.timestamps end

pool_tournament_match.rb

has_many :pool_tournament_match_relationships, class_name: 'PoolTournamentMatchRelationship', foreign_key: :parent_id has_many :parents, through: :pool_tournament_match_relationships

所以,我应该可以做match.pool_tournament_match_relationships.create(parent: anotherMatch)

之类的事情

但是,当我这样做时,添加到关系表中的记录实际上是match而不是anotherMatch的记录。因此,例如,如果match id为1而anotherMatch id为2.将在关系表中输入.1。

以下是控制台的输出:

m.pool_tournament_match_relationships.create(parent: m2)

INSERT INTO "pool_tournament_match_relationships" ("parent_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["parent_id", 1], ["created_at", 2016-11-08 21:51:29 UTC], ["updated_at", 2016-11-08 21:51:29 UTC]]

请注意,输入的parent_id为1,即m的id而不是m2。

irb(main):012:0> m.id => 1 irb(main):013:0> m2.id => 5

感谢您的帮助!

编辑:添加关系表的架构: create_table "pool_tournament_match_relationships", force: :cascade do |t| t.integer "parent_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["parent_id"], name: "index_pool_tournament_match_relationships_on_parent_id", using: :btree end

1 个答案:

答案 0 :(得分:0)

使用has-many-through关系,您不应该为创建关系表的记录或为其分配属性。只需在操作类上使用基本操作符,让Rails为您找出关系。

你的课程名称很长,而且我的工作方式并不是很直接,所以我会从我的一个项目中说明一些。

# app/models/event.rb

class Event < ActiveRecord::Base
  has_many :aid_stations, dependent: :destroy
  has_many :splits, through: :aid_stations
...
end

# app/models/split.rb

class Split < ActiveRecord::Base
  has_many :aid_stations, dependent: :destroy
  has_many :events, through: :aid_stations
...
end

# app/models/aid_station.rb

class AidStation < ActiveRecord::Base
  belongs_to :event
  belongs_to :split
...
end

# app/controllers/events_controller.rb

class EventsController < ApplicationController
  before_action :set_event
  ...

  def associate_split
    @event.splits << Split.find(params[:split_id])
    redirect_to splits_event_path(id: @event.id)
  end

  def remove_split
    @event.splits.delete(params[:split_id])
    redirect_to splits_event_path(@event)
  end

  private

  def set_event
    @event = Event.find(params[:id])
  end
end

请注意,associate_split会创建一个aid_station记录,remove_split会销毁一个,但是方法中没有提及任何aid_stations。 Rails负责幕后工作。

如果我选择将associateremove方法放在那里,这在splits_controller中同样有效。

编辑:这是aid_stations的架构的相关部分:

  create_table "aid_stations", force: :cascade do |t|
    t.integer  "event_id"
    t.integer  "split_id"
    ...
  end