简体   繁体   中英

How do I define a foreign key programatically?

Ruby 1.8.7-p249, Rails 2.3.8, SQLite3.

I'd like to create 2 tables programatically and define parent-child relationship between them. The foreign_key method does work in db migrations but it doesn't work in my code in ActiveRecord::Schema.define block .

How do I create a foreign key programatically?

Code:

# To change this template, choose Tools | Templates
# and open the template in the editor.

require "rubygems"
require "active_record"
require "logger"
require "pp"

ActiveRecord::Base.logger = Logger.new($stdout)

ActiveRecord::Base.establish_connection(
  :adapter  => "sqlite3",
  :database => "../db/development_mp.sqlite3"
)

ActiveRecord::Schema.define do
  create_table :orders, :force => true do |t|
    t.string   :name

    t.timestamps
  end

  create_table :invoices, :force => true do |t|    
    t.integer :order_id

    t.timestamps
  end

  # Error!
  foreign_key(:invoices, :order_id, :orders)
end

Error:

-- foreign_key(:invoices, :order_id, :orders) D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/migration.rb:352:in `send': undefined method `foreign_key' for
        #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x554f2f8> (NoMethodError)
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/migration.rb:352:in `method_missing'
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/migration.rb:328:in `say_with_time'
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/1.8/benchmark.rb:293:in `measure'
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/migration.rb:328:in `say_with_time'
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/migration.rb:348:in `method_missing'
                from D:/prg/Ruby/Pragmatic.Agile-Web-Development-With-Rails-Third-Edition/active_record_basics/lib/has_one_mp.rb:29
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/schema.rb:47:in `instance_eval'
                from D:/Ruby/bitnami-rubystack-2.1-0/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/schema.rb:47:in `define'
                from D:/prg/Ruby/Pragmatic.Agile-Web-Development-With-Rails-Third-Edition/active_record_basics/lib/has_one_mp.rb:16

You're already most of the way there, since you used the convention of [parent_table_name]_id for the foreign key (Good work!). Rails uses the convention over configuration model, so since you chose to name your foreign key order_id in your invoices table Rails will automatically figure out that order_id is the foreign key to the order.id primary key. All you need to do is specify in your models the has_many and belongs_to attributes.

/app/models/order.rb

class Order < ActiveRecord::Base

  has_many :invoices

end


----------


/app/models/invoice.rb

class Invoice < ActiveRecord::Base

  belongs_to :order

end

Note: If you named your foreign key in the invoices table something besides order_id (not recommended in Rails), let's say schmorder_id, then you would specify that it is the foreign key in your order model like such:

/app/models/order.rb

class Order < ActiveRecord::Base

  #if the foreign_key in your invoices table was named schmorder_id...
  has_many :invoices, :foreign_key => "schmorder_id"

end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM