我有一个属于LoadingStation模型的订单模型。装载工作站将在Order表中使用两次,因此看起来像:
class CreateLoadingStations < ActiveRecord::Migration[5.0]
def change
create_table :loading_stations do |t|
t.integer :type
t.string :comp_name1
t.string :street
t.string :street_num
t.string :zip_code
t.string :city
t.timestamps
end
end
end
class CreateOrders < ActiveRecord::Migration[5.0]
def change
create_table :orders do |t|
t.string :status
t.belongs_to :loading_station, class_name: "LoadingStation", index: true, foreign_key: "loading_station_id"
t.belongs_to :unloading_station, class_name: "LoadingStation", index: true, foreign_key: "unloading_station_id"
t.timestamps
end
end
end
当我运行 rails db:migrate 时出现此错误: ActiveRecord :: StatementInvalid:PG :: UndefinedTable:ERROR:relation&#34; unloading_stations&#34;不存在
嗯,似乎是检测到class_name不正确。两个语句中的class_name应该相同,对吗?
让我们检查装载站的型号:
class LoadingStation < ApplicationRecord
end
好的,我更改了CreateOrders迁移:
t.belongs_to :loading_station, class_name: "LoadingStation", index: true, foreign_key: "unloading_station_id"
现在,当我运行rails db:migrate时,我遇到了这个错误: ActiveRecord :: StatementInvalid:PG :: DuplicateObject:ERROR:constraint&#34; fk_rails_5294e269cc&#34;对于关系&#34;订单&#34;已存在
好的,我理解数据库中的外键似乎相同,数据库拒绝迁移任务。
但是当我定义了哪些不同的foreign_key名称,当数据库检测到两个相同的时候,foreign_key是什么意思:选项?
附录
这是我的订单模型:
class Order < ApplicationRecord
end
最终问题
最后 - 在错误消息中 - 我希望有两个外键指向同一个表。
答案 0 :(得分:1)
我将只关注允许您两次引用装载台表的代码
在Rails 5.1或更高版本中,您可以这样做:
class createOrders < ActiveRecord::Migration
def change
create_table(:orders) do |t|
t.references :loading_station, foreign_key: true
t.references :unloading_station, foreign_key: { to_table: 'loading_stations' }
end
end
end
这将创建字段loading_station_id
和unloading_station_id
,并在数据库级别引用loading_stations
表
class Order < ActiveRecord::Base
belongs_to :loading_station
belongs_to :unloading_station, class_name: "LoadingStation"
end
class LoadingStation < ActiveRecord::Base
has_many :load_orders, class_name: "Order", foreign_key: "loading_station_id"
has_many :unload_orders, class_name: "Order", foreign_key: "unloading_station_id"
end
答案 1 :(得分:0)
看起来你还没有创建一个unloading_station模型。
答案 2 :(得分:0)
关于创建以下内容的迁移,我没有遇到任何错误:
t.belongs_to :loading_station, class_name: "LoadingStation", index: true, foreign_key: "loading_station_id"
t.belongs_to :unloading_station, class_name: "LoadingStation", index: true, foreign_key: "unloading_station_id"
,Order表格如下:
Order(id: integer, status: string, loading_station_id: integer, unloading_station_id: integer, created_at: datetime, updated_at: datetime)
所以它有你需要的必要ID!
答案 3 :(得分:0)
我认为你们正在混淆迁移中应该包含的内容以及模型中应该包含的内容(我并不是以贬义的方式来表达这一点,所以请不要这样做。)
我已经整理了一个rails 5项目,以展示我认为你想要实现的目标:
总之,我相信您希望将加载和卸载工作站存储在一个表中,但是将它们作为订单的属性单独引用。换句话说,您正在寻找单表继承。
这是我快速建立的:
# app/models/order.rb
class Order < ApplicationRecord
belongs_to :loading_station, optional: true
belongs_to :unloading_station, optional: true
end
# app/models/station.rb
class Station < ApplicationRecord
end
# app/models/loading_station.rb
class LoadingStation < Station
has_many :orders
end
# app/models/unloading_station.rb
class UnloadingStation < Station
has_many :orders
end
正如您所见,LoadingStation
和UnloadingStation
模型继承了Station
模型。 Station
模型在数据库中获取一个表。
# db/migrate/20170826085833_create_orders.rb
class CreateStations < ActiveRecord::Migration[5.1]
def change
create_table :stations do |t|
t.string :comp_name1
t.string :street
t.string :street_num
t.string :zip_code
t.string :city
t.string :type, null: false
t.timestamps
end
end
end
type列定义为:string
并保存子类模型的类名,LoadingStation
或UnloadingStation
。
订单表迁移如下所示:
# db/migrate/20170826085833_create_orders.rb
class CreateOrders < ActiveRecord::Migration[5.1]
def change
create_table :orders do |t|
t.belongs_to :loading_station, null: true, index: true
t.belongs_to :unloading_station, null: true, index: true
t.string :status
end
end
end
如您所见,它引用了LoadingStation.id
和UnloadingStation.id
。我不确定这些属性是否是必需的,因此我将其设置为列定义中的null: false
和optional: true
模型中的Order
。
为了测试这是否有效,我在数据库种子中创建了一个LoadingStation,一个UnloadingStation和一个Order:
# db/seeds.rb
loading_station_1 = LoadingStation.create!(
comp_name1: "Loading Station 1",
street: "Park Ave",
street_num: "300",
zip_code: 10001,
city: "NY"
)
unloading_station_4 = UnloadingStation.create!(
comp_name1: "Unloading Station 4",
street: "Madison Ave",
street_num: "204",
zip_code: 10001,
city: "NY"
)
Order.create!(
loading_station: loading_station_1,
unloading_station: unloading_station_4,
status: "delivered"
)
要测试所有这些,只需创建数据库,运行迁移并执行种子:
rails db:create
rails db:migrate
rails db:seed
要测试结果,请打开rails console
:
irb(main):001:0> pp Station.all
Station Load (0.3ms) SELECT "stations".* FROM "stations"
[#<LoadingStation:0x007fcb8ac39440
id: 1,
comp_name1: "Loading Station 1",
street: "Park Ave",
street_num: "300",
zip_code: "10001",
city: "NY",
type: "LoadingStation",
created_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00,
updated_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00>,
#<UnloadingStation:0x007fcb8ac39288
id: 2,
comp_name1: "Unloading Station 4",
street: "Madison Ave",
street_num: "204",
zip_code: "10001",
city: "NY",
type: "UnloadingStation",
created_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00,
updated_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00>]
irb(main):002:0> pp Order.all
Order Load (0.2ms) SELECT "orders".* FROM "orders"
[#<Order:0x007fcb8bca2700
id: 1,
loading_station_id: 1,
unloading_station_id: 2,
status: "delivered">]
irb(main):003:0> order = Order.first
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Order id: 1, loading_station_id: 1, unloading_station_id: 2, status: "delivered">
irb(main):004:0> pp order.loading_station
LoadingStation Load (0.2ms) SELECT "stations".* FROM "stations" WHERE "stations"."type" IN ('LoadingStation') AND "stations"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
#<LoadingStation:0x007fcb8c0e4390
id: 1,
comp_name1: "Loading Station 1",
street: "Park Ave",
street_num: "300",
zip_code: "10001",
city: "NY",
type: "LoadingStation",
created_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00,
updated_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00>
irb(main):005:0> pp order.unloading_station
UnloadingStation Load (0.3ms) SELECT "stations".* FROM "stations" WHERE "stations"."type" IN ('UnloadingStation') AND "stations"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
#<UnloadingStation:0x007fcb8a36a378
id: 2,
comp_name1: "Unloading Station 4",
street: "Madison Ave",
street_num: "204",
zip_code: "10001",
city: "NY",
type: "UnloadingStation",
created_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00,
updated_at: Sat, 26 Aug 2017 09:06:53 UTC +00:00>
irb(main):006:0> pp order.status
"delivered"
我希望这会对你有所帮助。我已将代码检入github,您可以在https://github.com/JurgenJocubeit/SO-41796815访问它。