Amo*_*tir 21 migration ruby-on-rails
我正在寻找在rails中编写迁移的方法,这些方法可以多次针对数据库执行而不会失败.
比如说我有这个迁移:
class AddUrlToProfile < ActiveRecord::Migration
def self.up
add_column :profile, :url, :string
end
def self.down
remove_column :profile, :url
end
end
Run Code Online (Sandbox Code Playgroud)
如果该url
列已存在于Profile
表中(例如,如果schema.rb已被意外修改),我的迁移将失败,说它是重复的!
那么如果必须执行此迁移呢?
谢谢
Pan*_*kos 50
你可以这样做:
class AddUrlToProfile < ActiveRecord::Migration
def self.up
Profile.reset_column_information
add_column(:profile, :url, :string) unless Profile.column_names.include?('url')
end
def self.down
Profile.reset_column_information
remove_column(:profile, :url) if Profile.column_names.include?('url')
end
end
Run Code Online (Sandbox Code Playgroud)
这将在列信息开始之前重置列信息 - 确保配置文件模型具有实际表中的最新列信息.然后它只会添加列,如果它不存在.down函数也会发生同样的事情,但它只会删除列(如果存在).
如果您有多个用例,则可以将代码分解为函数并在迁移中重复使用.
Jel*_*Cat 15
对于Rails 3.X,有column_exists?(:table_name, :column_name)
方法.
对于Rails 2.X,您可以使用以下内容检查列的存在:
columns("<table name>").index {|col| col.name == "<column name>"}
Run Code Online (Sandbox Code Playgroud)
...或者如果您不在迁移文件中:
ActiveRecord::Base.connection.columns("<table name>").index {|col| col.name == "<column name>"}
Run Code Online (Sandbox Code Playgroud)
如果它返回nil,则不存在这样的列.如果它返回Fixnum,则该列确实存在.当然,{...}
如果您想要通过多个名称来标识列,您可以在更多选择性参数之间放置,例如:
{ |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil }
Run Code Online (Sandbox Code Playgroud)
这应该工作
def self.table_exists?(name)
ActiveRecord::Base.connection.tables.include?(name)
end
if table_exists?(:profile) && !Profile.column_names.include?("url")
add_column :profile, :url, :string
end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11033 次 |
最近记录: |