如何在Ruby on Rails中删除外键(如果存在)?

15

在ActionRecord中有一个名为index_exists?的函数,但是Rails 4.2.7没有foreign_key_exists?

因此,在一些数据库上调用remove_foreign_key:parties,franchise_groups时会出现错误。

我应该使用什么?


更新

我的代码

class RemoveForeignKey < ActiveRecord::Migration
  def up
    if foreign_key_exists?(:parties, :franchise_groups)
      remove_foreign_key :parties, :franchise_groups
    end
  end
end

出现错误

== 20161107163800 RemoveForeignKey: migrating =================================
-- foreign_key_exists?(:parties, :franchise_groups)
rake aborted!
An error has occurred, all later migrations canceled:

undefined method `foreign_key_exists?' for #<RemoveForeignKey:0x00000007ea0b58>
/home/rje/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.7/lib/active_record/migration.rb:664:in `block in method_missing'
6个回答

19

但是没有foreign_key_exists?吗?

foreign_key_exists?是存在的 :)

检查给定外键定义的表格是否存在外键。

# Checks to see if a foreign key exists.
  foreign_key_exists?(:accounts, :branches)

# 检查指定列上的外键是否存在。 foreign_key_exists?(:accounts, column: :owner_id)

# 检查具有自定义名称的外键是否存在。 foreign_key_exists?(:accounts, name: "special_fk_name")

或者您可以使用foreign_keys

if foreign_keys(:table_name).include?(foreign_key_name)
  # do stuff
end

谢谢。我现在在我的问题中提供了完整的错误信息。也许我没有理解文档。 - Richard
你能否在 up 方法内检查 self.class.included_modules.include?(ActiveRecord::ConnectionAdapters::SchemaStatements) 吗? - Andrey Deineko
puts self.class.included_modules.include?(ActiveRecord::ConnectionAdapters::SchemaStatements) 只是给我一个错误 uninitialized constant Connectio‌​nAdapters。也许在 Rails 4.2 上不存在这个东西? - Richard
@Richard 你可以使用 if foreign_keys(:accounts).include?(foreign_key_name) - Andrey Deineko
仅适用于Rails 5.0或更高版本。 - Tachyons

7
在Rails 4中,没有foreign_key_exists方法,因此我想出了以下解决方案:
remove_foreign_key :events, column: :subscribers_selector_id if foreign_keys(:events).map(&:column).include?("subscribers_selector_id")

2

我的Rails版本(Rails 4.2.6)似乎没有"foreign_key_exists?",所以我正在使用Array#any?来搜索从"foreign_keys"返回的结果,并确定是否存在给定的外键:

foreign_keys("parties").any?{|k| k[:to_table] == "franchise_groups"}

您可以这样使用它:
if foreign_keys("parties").any?{|k| k[:to_table] == "franchise_groups"}
remove_foreign_key :parties, column: :franchise_group_id
end

2

它依赖于连接:

ActiveRecord::Base.connection.foreign_key_exists?(:parties, :franchise_groups) 

2
我认为你可以使用类似于这样的东西。
def up
  remove_foreign_key :parties, column: :franchise_groups
end

def down
  add_foreign_key :parties, :franchise_groups
end

谢谢。但问题是先检查键是否存在,而不是删除它。 - Richard

1

Rails 7+ if_exists / if_not_exists选项

Rails 7添加了if_exists选项到remove_foreign_key中,以便在外键已经被删除时不会引发错误。

Rails 7添加了if_not_exists选项到add_foreign_key中,以便在外键已经添加时不会引发错误。

因此,可以按照以下方式编写迁移:

class RemoveFranchiseGroupForeignKeysFromParties < ActiveRecord::Migration
  def up
    remove_foreign_key :parties, :franchise_groups, if_exists: true
  end

  def down
    add_foreign_key :parties, :franchise_groups, if_not_exists: true
  end
end

来源:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接