202

I have a rake task that won't work unless a table exists. I'm working with more than 20 engineers on a website so I want to make sure they have migrated the table before they can do a rake task which will populate that respective table.

Does AR have a method such as Table.exists? How can I make sure they have migrated the table successfully?

strivedi183
  • 4,749
  • 2
  • 31
  • 38
thenengah
  • 42,557
  • 33
  • 113
  • 157
  • 14
    The joke goes.. how many engineers does it take to migrate a table :) – Zabba Jul 05 '11 at 23:47
  • 1
    On production 1. On Staging dozens and multiple times each . – thenengah Jul 05 '11 at 23:48
  • 2
    Wouldn't it be easier just run the migrations on the start of your rake task? So you don't have to worry about missing tables. – raskhadafi Jul 24 '12 at 20:48
  • @raskhadafi : Note that missing tables are going to give you a problem if your config/initializers use them. (i.e. even `rake db:migrate` will fail.) – ocodo Sep 23 '16 at 05:45

5 Answers5

343

In Rails 5 the API became explicit regarding tables/views, collectively data sources.

# Tables and views
ActiveRecord::Base.connection.data_sources
ActiveRecord::Base.connection.data_source_exists? 'kittens'

# Tables
ActiveRecord::Base.connection.tables
ActiveRecord::Base.connection.table_exists? 'kittens'

# Views
ActiveRecord::Base.connection.views
ActiveRecord::Base.connection.view_exists? 'kittens'

In Rails 2, 3 & 4 the API is about tables.

# Listing of all tables and views
ActiveRecord::Base.connection.tables

# Checks for existence of kittens table/view (Kitten model)
ActiveRecord::Base.connection.table_exists? 'kittens'

Getting the status of migrations:

# Tells you all migrations run
ActiveRecord::Migrator.get_all_versions

# Tells you the current schema version
ActiveRecord::Migrator.current_version

If you need more APIs for migrations or metadata see:

captainpete
  • 6,162
  • 3
  • 28
  • 26
  • 4
    `ActiveRecord::Base.connection.table_exist 'users'` would check for a users table. – thenengah Jul 05 '11 at 23:56
  • 4
    `ActiveRecord::Base.connection.table_exists? 'kittens` would check for a Kitten table. That is unless I destroyed all kittens! `drop_table :kittens` – thenengah Jul 05 '11 at 23:59
  • 1
    Thanks guys! I just used `.index_exists?('kittens', 'paws')` – Trip Oct 26 '12 at 15:34
  • 14
    This works for ActiveRecord 3.2.11 `drop_table(:hosts_users) if table_exists? :hosts_users` – Greg Feb 13 '13 at 13:46
  • `current_version` was just what I needed to disable a model method long enough to allow its migrations to run when I finally deployed it to production. Thanks! – Becca Royal-Gordon Feb 26 '15 at 20:57
  • 1
    `ActiveRecord::Base.connection.data_source_exists? 'table_name'` is the correct one now – Dorian Dec 30 '16 at 01:35
62

even if table is not exists:

model Kitten, expected table kittens rails 3:

Kitten.table_exists? #=> false

alexey_the_cat
  • 1,812
  • 19
  • 33
39

I found this out while I was trying to remove a table via a migration:

drop_table :kittens if (table_exists? :kittens)
ActiveRecord::Migration.drop_table :kittens if (ActiveRecord::Base.connection.table_exists? :kittens)

works for Rails 3.2

This simpler form will become available in Rails 5:

drop_table :kittens, if_exists: true

Reference: https://github.com/rails/rails/pull/16366

And here's the Rails 5 ActiveRecord's CHANGELOG:

Introduce the :if_exists option for drop_table.

Example:

drop_table(:posts, if_exists: true)

That would execute:

DROP TABLE IF EXISTS posts

If the table doesn't exist, if_exists: false (the default) raises an exception whereas if_exists: true does nothing.

Evgeniya Manolova
  • 2,542
  • 27
  • 21
kangkyu
  • 5,252
  • 3
  • 34
  • 36
  • This will fail if the table is in fact a view, as the table will appear to exist, but DROP TABLE can not drop it. – mcr Mar 29 '16 at 14:34
14

Rails 5.1

if ActiveRecord::Base.connection.data_source_exists? 'table_name'
   drop_table :table_name
end

or

drop_table :table_name, if_exists: true
Vitor Oliveira
  • 414
  • 3
  • 13
  • 2
    table_exists still works in rails-5, but its behavior will be changing to only check tables. As of 5.0.1 it checks views and tables. data_source_exists keeps that behavior and table_exists will be changing to only check tables. – John Naegle Jan 14 '17 at 20:19
  • He is not asking to check the table on a migration, he needs to be sure that the table exists on a rake task – Juan Furattini Jan 27 '19 at 06:25
3

The proper way to do this is Model.table_exists?

class Dog < ApplicationRecord
  # something
end

do_something if Dog.table_exists?
Juan Furattini
  • 776
  • 6
  • 9