Hopp til innholdet

cjohansen.no

Fremmednøkler i Rails

Av en eller annen grunn har ikke folkene bak Rails mye til overs for fremmednøkler. Heldigvis finnes det løsninger for oss som syntes at dataintegritet er viktigere enn å være database-agnostisk.

Rails 2 lurer deg

I Rails 2 kan du gjøre følgende i migrations:

create_table :employee do |t|
      t.references :company
end

Men ikke la deg lure; references gjør stort sett ikke annet enn å lage et integer-felt ved navn company_id. Ingen fremmednøkkel blir opprettet.

Mange løsninger

Det er forholdsvis simpelt å jobbe seg rundt. Tidligere har jeg ofte brukt RedHills plugin for fremmednøkler i migrations, og den funker bra. Idag kom jeg tilfeldigvis over en annen løsning som er litt simplere på railsforum.com:

[RAILS_ROOT]/lib/migration_helpers.rb:

# http://www.railsforum.com/viewtopic.php?pid=59362, noe modifisert
module MigrationHelpers
  def add_foreign_key(from_table, from_column, to_table)
    constraint_name = "fk_#{from_table}_#{from_column}"

    execute "alter table #{from_table} add constraint #{constraint_name} " +
            "foreign key (#{from_column}) references #{to_table}(id)"
  end

  def remove_foreign_key(from_table, from_column)
    constraint_name = "fk_#{from_table}_#{from_column}"

    execute "alter table #{from_table} drop foreign key #{constraint_name}"
  end
end

Deretter kan du gjøre følgende i migrations:

class CreateEmployees < ActiveRecord::Migration
  def self.up
    create_table :employees do |t|
      t.references :company
      t.string :name
    end

    add_foreign_key :employees, :company_id, :companies
  end

  def self.down
    # Ikke egentlig nødvendig når du fjerner tabellen, men...
    remove_foreign_key :employees, :company_id
    drop_table :employees
  end
end

Dette fungerer aldeles glimrende. Du kan også legge til fremmednøkler til eksisterende tabeller (med eksisterende data) gjennom migrations på denne måten også. RedHill-pluginen funker fortsatt, men dette er litt mindre kode, og en litt simplere løsning.

NB! Denne løsningen er MySQL-spesifikk, så tilpass til egne behov.

Muligens relatert

2006 - 2010 Christian Johansen Creative Commons Lisens