How to write conditional migrations in rails?

前端 未结 4 602
悲&欢浪女
悲&欢浪女 2020-12-30 01:14

I am looking for ways to write migrations in rails that can be executed against the database many times without failing.

For instance let say I have this migration:

相关标签:
4条回答
  • 2020-12-30 01:17

    You can do something like this:

    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
    

    This will reset the column information before it begins - making sure that the Profile model has the up-to-date column information from the actual table. It will then only add the column if it doesn't exist. The same thing happens for the down function, but it only removes the column if it exists.

    If you have multiple use cases for this you could factor the code out into a function and re-use that in your migrations.

    0 讨论(0)
  • 2020-12-30 01:19

    For Rails 3.X, there's the column_exists?(:table_name, :column_name) method.

    For Rails 2.X, you can check the existence of columns with the following:

    columns("<table name>").index {|col| col.name == "<column name>"}
    

    ...or if you're not in a migration file:

    ActiveRecord::Base.connection.columns("<table name>").index {|col| col.name == "<column name>"}
    

    If it returns nil, no such column exists. If it returns a Fixnum, then the column does exist. Naturally, you can put more selective parameters between the {...} if you want to identify a column by more than just its name, for example:

    { |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil }
    
    0 讨论(0)
  • 2020-12-30 01:24

    Wrapping my migration in a conditional worked for me. Rails 4.X

    class AddUrlToProfile < ActiveRecord::Migration
      unless Profile.column_names.include?("url")
        def self.up
          add_column :profile, :url, :string
        end
    
        def self.down
          remove_column :profile, :url
        end
      end
    end 
    
    0 讨论(0)
  • 2020-12-30 01:28

    This should work

    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
    
    0 讨论(0)
提交回复
热议问题