การโอนย้าย Rails สำหรับ has_and_belongs_to_many join table


122

ฉันscript/generate migrationจะสร้างตารางการเข้าร่วมสำหรับhas_and_belongs_to_manyความสัมพันธ์ได้อย่างไร

แอปพลิเคชันทำงานบน Rails 2.3.2 แต่ฉันติดตั้ง Rails 3.0.3 ไว้ด้วย

คำตอบ:


228

ที่ไหน:

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :students
end

และ

class Student < ActiveRecord::Base
  has_and_belongs_to_many :teachers
end

สำหรับราง 4:

rails generate migration CreateJoinTableStudentTeacher student teacher

สำหรับราง 3:

rails generate migration students_teachers student_id:integer teacher_id:integer

สำหรับราง <3

script/generate migration students_teachers student_id:integer teacher_id:integer

(สังเกตชื่อตารางจะแสดงทั้งตารางรวมตามลำดับตัวอักษร)

จากนั้นสำหรับราง 3 และต่ำกว่าเท่านั้นคุณต้องแก้ไขการย้ายข้อมูลที่สร้างขึ้นเพื่อไม่ให้สร้างฟิลด์ id:

create_table :students_teachers, :id => false do |t|

16
นี่เป็นคำตอบเดียวที่ตอบคำถามได้จริง
pingu

8
@pingu: ยกเว้นว่าจะไม่ทำงานอย่างน้อยใน Rails 3.2 ไฟล์การย้ายข้อมูลที่สร้างขึ้นว่างเปล่า
hoffmanc

7
ใช้งานได้กับ Rails 4
Felipe Zavan

2
@hoffmanc มันจะสร้างไฟล์การย้ายข้อมูลที่ว่างเปล่าหากคุณไม่ได้ระบุฟิลด์ใด ๆ คุณต้องระบุฟิลด์หากคุณต้องการให้ Rails เพิ่มลงในไฟล์โอนย้ายโดยอัตโนมัติ
Andrew

1
สวัสดีฉันกำลังพยายามrails generate migration CreateJoinTableTeacherStudent teacher studentแทนที่จะrails generate migration CreateJoinTableStudentTeacher student teacherเป็นแบบนั้นใช่ไหม S (tudent) จำเป็นต้องอยู่ก่อน T (eacher) หรือไม่?
zx1986

138

has_and_belongs_to_manyตารางจะต้องตรงกับรูปแบบนี้ ฉันสมมติว่าทั้งสองรุ่นที่จะเข้าร่วมhas_and_belongs_to_manyนั้นมีอยู่แล้วในฐานข้อมูล: applesและoranges:

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables. Don't use the
# unique if you allow duplicates.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)

ถ้าคุณใช้:unique => trueดัชนีแล้วคุณควร (ใน rails3) ผ่านไป:uniq => truehas_and_belongs_to_many

ข้อมูลเพิ่มเติม: Rails Docs

อัปเดต2010-12-13ฉันได้อัปเดตเพื่อลบรหัสและการประทับเวลา ... โดยทั่วไปMattDiPasqualeและnunopoloniaถูกต้อง: ต้องไม่มีรหัสและต้องไม่มีการประทับเวลามิฉะนั้นรางจะไม่อนุญาตให้has_and_belongs_to_manyทำงาน


6
จริงๆแล้วตารางรวมควรมีคอลัมน์อ้างอิงสองคอลัมน์เท่านั้นและไม่มีคอลัมน์รหัสหรือการประทับเวลา นี่คือตัวอย่างที่ดีกว่าของการย้ายข้อมูล has_and_belongs_to_manyจากลิงก์ที่คุณให้มา ฉันกำลังมองหาวิธีที่จะทำได้จากบรรทัดคำสั่งด้วยscript/generate migration...
ma11hew28

ไม่จำเป็นต้องมีการประทับเวลา ฉันทำเครื่องหมายเป็นตัวเลือกในตัวอย่างของฉัน ฉันอยากจะแนะนำให้เพิ่มรหัสแม้ว่า มีหลายกรณีที่ ID หรือการประทับเวลาอาจเป็นประโยชน์ แต่ผมขอแนะนำ ID
docwhat

ตกลง. อะไรคือกรณีที่ ID จะมีประโยชน์?
ma11hew28

ตัวอย่างหนึ่งคือถ้าความสัมพันธ์มีความสำคัญมากพอที่จะมีมุมมอง นอกจากนี้ยังสามารถใช้เพื่อเพิ่มความเร็วในการเข้าถึงฐานข้อมูลโดยส่งผ่านความสัมพันธ์ id แทนการค้นหาซ้ำ ๆ นอกจากนี้ยังทำให้การแก้ไขปัญหาฐานข้อมูลง่ายขึ้น โดยเฉพาะอย่างยิ่งถ้ารหัสของคอลัมน์อื่นสูงมาก ง่ายกว่าที่จะจำ id: 12345 แทนที่จะเป็น id: 54321-id: 67890 - แต่อย่างที่กล่าวไว้ถ้าตารางมีขนาดใหญ่มากคุณอาจต้องการประหยัดพื้นที่โดยไม่จัดสรร id อื่นสำหรับแต่ละความสัมพันธ์
docwhat

2
ฉันไม่คิดว่าดัชนีหลายคอลัมน์เป็นทางออกที่เหมาะสมสำหรับสิ่งนี้ จะใช้สำหรับการค้นหาสำหรับแอปเปิ้ลโดยเฉพาะเพื่อค้นหาส้มที่เกี่ยวข้อง แต่ไม่ใช่ในทางกลับกัน ดัชนีคอลัมน์เดียวสองรายการจะช่วยให้สามารถสืบค้นทั้งสองทิศทางได้อย่างมีประสิทธิภาพซึ่งอาจสูญเสียการตรวจสอบการดำรงอยู่ของแอปเปิ้ลส้มโดยเฉพาะ)
Joseph Lord

14

คุณควรตั้งชื่อตารางเป็นชื่อของ 2 รุ่นที่คุณต้องการเชื่อมต่อตามลำดับตัวอักษรและใส่รหัสรุ่นทั้งสองในตาราง จากนั้นเชื่อมต่อแต่ละรุ่นเข้าด้วยกันเพื่อสร้างการเชื่อมโยงในแบบจำลอง

นี่คือตัวอย่าง:

# in migration
def self.up
  create_table 'categories_products', :id => false do |t|
    t.column :category_id, :integer
    t.column :product_id, :integer
  end
end

# models/product.rb
has_and_belongs_to_many :categories

# models/category.rb
has_and_belongs_to_many :products

แต่สิ่งนี้ไม่ยืดหยุ่นมากนักและคุณควรคำนึงถึงการใช้ has_many: through


6

คำตอบด้านบนแสดงดัชนีผสมที่ฉันไม่เชื่อว่าจะใช้ในการค้นหาแอปเปิ้ลจากส้ม

create_table :apples_oranges, :id => false do |t|
  t.references :apple, :null => false
  t.references :orange, :null => false
end

# Adding the index can massively speed up join tables.
# This enforces uniqueness and speeds up apple->oranges lookups.
add_index(:apples_oranges, [:apple_id, :orange_id], :unique => true)
# This speeds up orange->apple lookups
add_index(:apples_oranges, :orange_id)

ฉันพบว่าคำตอบนี้อ้างอิงจาก 'The Doctor What' มีประโยชน์และการสนทนาก็เช่นกัน


4

ในราง 4 คุณสามารถใช้งานได้ง่าย

create_join_table: table1s,: table2s

มันคือทั้งหมด.

ข้อควรระวัง: คุณต้อง offord table1, table2 ด้วยตัวอักษรและตัวเลข


นี่เป็นวิธีการแก้ปัญหาที่ดี หมายเหตุตารางเข้าร่วมไม่สามารถเข้าถึงได้ในรูปแบบ แต่ผ่านความสัมพันธ์ has_and_belongs_to_many ที่ตั้งค่าบนทั้งสองตารางที่เข้าร่วม
เว็บไซต์

1

ฉันชอบทำ:

rails g migration CreateJoinedTable model1:references model2:references. ด้วยวิธีนี้ฉันจะได้รับการโยกย้ายที่มีลักษณะดังนี้:

class CreateJoinedTable < ActiveRecord::Migration
  def change
    create_table :joined_tables do |t|
      t.references :trip, index: true
      t.references :category, index: true
    end
    add_foreign_key :joined_tables, :trips
    add_foreign_key :joined_tables, :categories
  end
end

ฉันชอบมีดัชนีในคอลัมน์เหล่านี้เพราะฉันมักจะทำการค้นหาโดยใช้คอลัมน์เหล่านี้


add_foreign_keyจะล้มเหลวหากอยู่ในการโยกย้ายเดียวกันกับที่สร้างตาราง
Adib Saad
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.