135

I know that you can ask ActiveRecord to list tables in console using:

ActiveRecord::Base.connection.tables

Is there a command that would list the columns in a given table?

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Andrew
  • 42,517
  • 51
  • 181
  • 281

9 Answers9

251

This will list the column_names from a table

Model.column_names
e.g. User.column_names
Pravin
  • 6,592
  • 4
  • 42
  • 51
  • 20
    You could also run something like `Model.columns` to get more info about the columns including database config data. – srt32 Apr 21 '14 at 18:18
  • 1
    Great! Using `Model.columns` provides all the information for a table through ActiveRecord. Crucially for me it was the only and easiest way to gain confidence in what my __primary key__ really was at the database level. – nibbex Mar 11 '15 at 17:30
  • 2
    You could always use Model.primary_key, which gives you the name of the primary key according to rails. (This will be 'id' unless it's declared in the model as something else). – AJFaraday Nov 25 '15 at 10:24
67

This gets the columns, not just the column names and uses ActiveRecord::Base::Connection, so no models are necessary. Handy for quickly outputting the structure of a db.

ActiveRecord::Base.connection.tables.each do |table_name|
  puts table_name
  ActiveRecord::Base.connection.columns(table_name).each do |c| 
    puts "- #{c.name}: #{c.type} #{c.limit}"
  end
end

Sample output: http://screencast.com/t/EsNlvJEqM

Flavio Wuensche
  • 9,460
  • 1
  • 57
  • 54
Aaron Henderson
  • 1,840
  • 21
  • 20
  • In rails 3.2, doing it this way somehow doesn't set the `primary` attribute correctly (all columns have `primary=nil`). It is set correctly with the `Model.columns` method suggested by srt32. – sayap Apr 24 '14 at 04:17
  • 1
    This is the right answer. There is no requirement to have a model. Not every table has a model. "has_many_and_belongs_to" – baash05 Mar 11 '20 at 02:21
  • To provide a list sorted by table name, use: ActiveRecord::Base.connection.tables.sort.each – Richard_G Mar 20 '21 at 15:23
23

Using rails three you can just type the model name:

> User
gives:
User(id: integer, name: string, email: string, etc...)

In rails four, you need to establish a connection first:

irb(main):001:0> User
=> User (call 'User.connection' to establish a connection)
irb(main):002:0> User.connection; nil #call nil to stop repl spitting out the connection object (long)
=> nil
irb(main):003:0> User
User(id: integer, name: string, email: string, etc...)
Yule
  • 9,668
  • 3
  • 51
  • 72
  • OP just wants the column names. – Ryan Bigg Apr 07 '11 at 07:04
  • Perhaps. But not necessarily. It is an alternative way of getting them with extra info that is sometimes helpful when listing columns from console – Yule Apr 07 '11 at 07:07
  • 1
    This is also a useful method to know, IMO. @Yule - does this query the schema/migrations code etc. or does it query the DB? The reason I ask is I was experiencing a mismatch between my schema and what actually was in the DB (one migration glitched), so specifically I needed to be sure I was seeing what was actually in the table. – Andrew Apr 07 '11 at 13:17
  • @Andrew it queries the DB (hence the need to establish a connection in rails 4) – Yule Dec 02 '14 at 09:15
8

complementing this useful information, for example using rails console o rails dbconsole:

Student is my Model, using rails console:

$ rails console
> Student.column_names
 => ["id", "name", "surname", "created_at", "updated_at"] 

> Student
 => Student(id: integer, name: string, surname: string, created_at: datetime, updated_at: datetime)

Other option using SQLite through Rails:

$ rails dbconsole

sqlite> .help

sqlite> .table
ar_internal_metadata  relatives             schools             
relationships         schema_migrations     students 

sqlite> .schema students
CREATE TABLE "students" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "surname" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);

Finally for more information.

sqlite> .help

Hope this helps!

Gamaliel
  • 455
  • 6
  • 5
7

If you are comfortable with SQL commands, you can enter your app's folder and run rails db, which is a brief form of rails dbconsole. It will enter the shell of your database, whether it is sqlite or mysql.

Then, you can query the table columns using sql command like:

pragma table_info(your_table);
gm2008
  • 4,245
  • 1
  • 36
  • 38
2

You can run rails dbconsole in you command line tool to open sqlite console. Then type in .tables to list all the tables and .fullschema to get a list of all tables with column names and types.

codeepic
  • 3,723
  • 7
  • 36
  • 57
  • You can use online database console (gem [activeadmin-sqlpage](https://github.com/oklas/activeadmin-sqlpage)) as describerd in [this answer](http://stackoverflow.com/a/43159348/2969544) if you use active admin. – oklas Apr 01 '17 at 16:45
2
  • To list the columns in a table I usually go with this:
    Model.column_names.sort.
    i.e. Orders.column_names.sort

    Sorting the column names makes it easy to find what you are looking for.

  • For more information on each of the columns use this:
    Model.columns.map{|column| [column.name, column.sql_type]}.to_h.

This will provide a nice hash. for example:

{
   id => int(4),
   created_at => datetime
}
csebryam
  • 1,091
  • 11
  • 13
1

I am using rails 6.1 and have built a simple rake task for this.

You can invoke this from the cli using rails db:list[users] if you want a simple output with field names. If you want all the details then do rails db:list[users,1].

I constructed this from this question How to pass command line arguments to a rake task about passing command line arguments to rake tasks. I also built on @aaron-henderson's answer above.

# run like `rails db:list[users]`, `rails db:list[users,1]`, `RAILS_ENV=development rails db:list[users]` etc
namespace :db do
  desc "list fields/details on a model"
  task :list, [:model, :details] => [:environment] do |task, args|
    model = args[:model]
    if !args[:details].present?
      model.camelize.constantize.column_names.each do |column_name|
        puts column_name
      end
    else
      ActiveRecord::Base.connection.tables.each do |table_name|
        next if table_name != model.underscore.pluralize
        ActiveRecord::Base.connection.columns(table_name).each do |c|
          puts "Name: #{c.name} | Type: #{c.type} | Default: #{c.default} | Limit: #{c.limit} | Precision: #{c.precision} | Scale: #{c.scale} | Nullable: #{c.null} "
        end
      end
    end
  end
end
Jay Killeen
  • 2,832
  • 6
  • 39
  • 66
0

For a more compact format, and less typing just:

Portfolio.column_types 
valk
  • 9,363
  • 12
  • 59
  • 79
  • Does not exist in rails 5+ – Pak Oct 18 '19 at 15:16
  • The answer doesn't state that, and the question is tagged Rails 3 @Pak... – Sebastián Palma Apr 10 '21 at 16:00
  • @SebastianPalma I know, but as this is a well-referenced question such comments are imo helpful for people looking for answers, fast. The tag was probably chosen during the initial write-up but the question is quite generic. – Pak Apr 12 '21 at 18:25