Thêm di chuyển cột tham chiếu trong Rails 4


310

Một người dùng có nhiều lượt tải lên. Tôi muốn thêm một cột vào uploadsbảng tham chiếu đến user. Việc di chuyển nên như thế nào?

Đây là những gì tôi có. Tôi không chắc mình nên sử dụng (1) :user_id, :inthay (2) :user, :references. Tôi thậm chí không chắc chắn nếu (2) hoạt động. Chỉ cần cố gắng để làm điều này theo cách "đường ray".

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_column :uploads, :user_id, :integer
  end
end

Câu hỏi liên quan ngoại trừ Rails 3. Rails 3 di chuyển: Thêm cột tham chiếu?

Câu trả lời:


706

Đường ray 4.x

Khi bạn đã có usersuploadscác bảng và muốn thêm một mối quan hệ mới giữa chúng.

Tất cả những gì bạn cần làm là: chỉ cần tạo một di chuyển bằng lệnh sau:

rails g migration AddUserToUploads user:references

Mà sẽ tạo một tệp di chuyển như:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
  end
end

Sau đó, chạy di chuyển bằng cách sử dụng rake db:migrate. Việc di chuyển này sẽ đảm nhiệm việc thêm một cột mới được đặt tên user_idvào uploadsbảng ( idcột tham chiếu trong usersbảng), PLUS cũng sẽ thêm một chỉ mục trên cột mới.

CẬP NHẬT [Đối với Rails 4.2]

Rails không thể được tin cậy để duy trì tính toàn vẹn tham chiếu; cơ sở dữ liệu quan hệ đến để giải cứu của chúng tôi ở đây. Điều đó có nghĩa là chúng ta có thể thêm các ràng buộc khóa ngoài ở cấp cơ sở dữ liệu và đảm bảo rằng cơ sở dữ liệu sẽ từ chối mọi hoạt động vi phạm tính toàn vẹn tham chiếu đã đặt này. Như @infoget đã nhận xét, Rails 4.2 xuất xưởng với sự hỗ trợ riêng cho các khóa ngoại (tính toàn vẹn tham chiếu) . Không bắt buộc nhưng bạn có thể muốn thêm khóa ngoại (vì nó rất hữu ích) vào tham chiếu mà chúng tôi đã tạo ở trên.

Để thêm khóa ngoại vào tham chiếu hiện có , hãy tạo một di chuyển mới để thêm khóa ngoại:

class AddForeignKeyToUploads < ActiveRecord::Migration
  def change
    add_foreign_key :uploads, :users
  end
end

Để tạo một tham chiếu hoàn toàn mới với khóa ngoại (trong Rails 4.2) , hãy tạo một di chuyển bằng lệnh sau:

rails g migration AddUserToUploads user:references

sẽ tạo một tệp di chuyển như:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
    add_foreign_key :uploads, :users
  end
end

Điều này sẽ thêm một khóa ngoại mới vào user_idcột của uploadsbảng. Khóa tham chiếu idcột trong usersbảng.

LƯU Ý: Điều này ngoài việc thêm một tham chiếu, do đó bạn vẫn cần tạo một tham chiếu trước sau đó là khóa ngoại ( bạn có thể chọn tạo khóa ngoại trong cùng một di chuyển hoặc một tệp di chuyển riêng ). Active Record chỉ hỗ trợ các khóa ngoại cột đơn và hiện tại mysql, mysql2PostgreSQLcác bộ điều hợp được hỗ trợ. Đừng thử điều này với các bộ điều hợp khác như sqlite3, v.v. Tham khảo Hướng dẫn của Rails: Khóa ngoài để bạn tham khảo.


8
Trong nhiều trường hợp, tốt hơn là thêm khóa ngoại. add_forign_key (Rails 4.2)
poerror

18
Tôi tin rằng bạn có thể thực hiện tất cả trong một dòng: add_Vference: tải lên ,: người dùng, chỉ mục: true, Foreign_key: true @KirtiThorat
user1801879

32
Bây giờ, nếu bạn sử dụng cú pháp trình tạo đặc biệt để di chuyển, Rails 4.2 sẽ tự động tạo di chuyển chính xác với các ràng buộc khóa ngoài được bao gồm. rails g migration AddUserToUploads user:referencessản xuất add_reference :uploads, :user, index: true, foreign_key: truetrong việc di chuyển thích hợp.
jrhorn424

10
Sử dụng ...index: true, foreign_key: truethay thế o dòng add_foreign_key.
Washington Botelho

2
Tại sao chúng ta cần cả hai foreign_keyt.reference? t.referenceVề cơ bản không tương đương với foriegn_key+ index?
Geoboy

188

Đường ray 5

Bạn vẫn có thể sử dụng lệnh này để tạo di chuyển:

rails g migration AddUserToUploads user:references

Việc di chuyển có vẻ hơi khác so với trước đây, nhưng vẫn hoạt động:

class AddUserToUploads < ActiveRecord::Migration[5.0]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Lưu ý rằng nó :user, không phải:user_id


2
Đối với các lớp cách nhau tên, như Local::Userthay vì Userlàm một cái gì đó như rails g migration AddLocalUserToUploads user:references.
Ka Mok

3
điều này có tự động thêm không:index
Saravanabalagi Ramachandran

4
@Zeke Có, hãy chạy di chuyển và kiểm tra lược đồ của bạn, nó sẽ có nội dung giống nhưt.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318

1
vâng, tôi đã gặp lỗi "chỉ mục tồn tại" khi tôi thêm thủ công add_index khi di chuyển: P @ Mirror318
Saravanabalagi Ramachandran

2
Chúng ta cũng nên thêm belongs_to :uservào Uploadlớp, vì vậy chúng ta có thể sử dụng upload.userđể lấy cá thể người dùng.
Wit

17

nếu bạn thích một phương pháp thay thế khác updownphương pháp hãy thử điều này:

  def up
    change_table :uploads do |t|
      t.references :user, index: true
    end
  end

  def down
    change_table :uploads do |t|
      t.remove_references :user, index: true
    end
  end

9

[Sử dụng Rails 5]

Tạo di chuyển:

rails generate migration add_user_reference_to_uploads user:references

Điều này sẽ tạo tập tin di chuyển:

class AddUserReferenceToUploads < ActiveRecord::Migration[5.1]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Bây giờ nếu bạn quan sát tệp lược đồ, bạn sẽ thấy bảng tải lên chứa một trường mới. Một cái gì đó như: t.bigint "user_id"hoặc t.integer "user_id".

Di chuyển cơ sở dữ liệu:

rails db:migrate

1
Câu trả lời này dường như trùng lặp với câu trả lời của @ Mirror318. Hãy bình luận về câu trả lời trên nếu bạn nghĩ thiếu một cái gì đó từ nó. Cảm ơn.
M. Habib

8

Một cú pháp khác để làm điều tương tự là:

rails g migration AddUserToUpload user:belongs_to

7

Chỉ cần ghi lại nếu ai đó có cùng một vấn đề ...

Trong tình huống của tôi, tôi đã sử dụng :uuidcác trường và các câu trả lời ở trên không hoạt động với trường hợp của tôi, vì đường ray 5 đang tạo một cột bằng cách sử dụng :bigintthay thế :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users

Nó cũng rõ ràng hơn nhiều những gì đang xảy ra. Nhưng vâng, UUID phải là tiêu chuẩn.
ngày

2

Tạo một tệp di chuyển

rails generate migration add_references_to_uploads user:references

Tên khóa ngoại mặc định

Điều này sẽ tạo một cột user_id trong bảng tải lên dưới dạng khóa ngoại

class AddReferencesToUploads < ActiveRecord::Migration[5.2]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

mô hình người dùng:

class User < ApplicationRecord
  has_many :uploads
end

mô hình tải lên:

class Upload < ApplicationRecord
  belongs_to :user
end

Tùy chỉnh tên khóa ngoại:

add_reference :uploads, :author, references: :user, foreign_key: true

Điều này sẽ tạo một cột Author_id trong các bảng tải lên dưới dạng khóa ngoại.

mô hình người dùng:

class User < ApplicationRecord
  has_many :uploads, foreign_key: 'author_id'
end

mô hình tải lên:

class Upload < ApplicationRecord
  belongs_to :user
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.