Rails Tasks: exporting database models to a CSV.
Tags: ruby, rails, tasks, csv
Published: 2020-04-13 19:05:30


If you just want the code, scroll to the bottom 🥳

Rails has some really nice ways to make a developers life a bit easier. One of them is Rake Tasks. If you have ever executed the command `rails c`, or `rake db:migrate`, you've already used tasks. Since version 5.0, Rails allows you to call most rake commands with `rails` instead.

### A bit of background
We needed an automated and simple way to share our database design across the company. A schema file didn't cut it. 

[ERD gem](https://github.com/voormedia/rails-erd) is a great option to share the high level overview. We use it all the time. It generates a nice PDF showing model associations and attributes (tutorial to come shortly).

But for the nitty gritty details we made a task which exports our database models, attributes and data types to a CSV.

---

__Let's break it down.__

- Create a `models_to_csv.rake` file over in `lib/tasks`.
- `require 'csv'` (built into Rails) to be able to generate CSV's.
- Define your task name and list under an optional namespace.

```ruby
# lib/tasks/models_to_csv.rake

require 'csv'

namespace :custom do
  desc 'Generate a CSV with all models, attribute names, and attribute database types'

  task models_to_csv: :environment do
  end

end
```

- Load all your database models into memory. Rails does not `eager_load` by default in Rake Tasks. Note for Rails 5 and below, you should do `Rails.application.eager_load!`
- Define where you want to save the CSV.
- Set the column names you want. Three names equals three columns.
- Open up the CSV block and pass in the `headers`.

```ruby
# lib/tasks/models_to_csv.rake

require 'csv'

namespace :custom do
  desc 'Generate a CSV with all models, attribute names, and attribute database types'

  task models_to_csv: :environment do

    Zeitwerk::Loader.eager_load_all
    file = Rails.root.join('public/model_data.csv')
    headers = %w[Model Attribute Type].freeze

    CSV.open(file, 'w', write_headers: true, headers: headers) do |writer|
    end
  end
end

```

__Right! Thats the set up done. Next we need to loop through all our model attributes and generate the CSV.__

- Iterate over `ActiveRecord::Base.descendants` to get your models.
- Skip any models you don't want.
- Iterate over each models attributes.
- Add the model name, attribute and attribute data type to the CSV writer.
- Profit 💸



```ruby
# lib/tasks/models_to_csv.rake

require 'csv'

namespace :custom do
  desc 'Generate a CSV with all models, attribute names, and attribute database types'

  task models_to_csv: :environment do

    Zeitwerk::Loader.eager_load_all
    file = Rails.root.join('public/model_data.csv')
    headers = %w[Model Attribute Type].freeze

    CSV.open(file, 'w', write_headers: true, headers: headers) do |writer|
      ActiveRecord::Base.descendants.each do |model|
        next if model.name.starts_with?('ActiveStorage')

        model.attribute_names.each do |attribute|
          writer << [model.name, attribute, model.columns_hash[attribute].type.to_s]
        end
      end
    end
    puts 'CSV generated here -> /public/model_data.csv'
  end
end

```

__Awesome. Now all we need to do is run our new task.__

`rails custom:models_to_csv`

---

PS. We are looking for great [Product Engineers](https://angel.co/company/imagine-mortgages/jobs) over at [Generation Home](https://generationhome.com/). We are a funded, UK based, pre-launch tech company, tying to create more ways into home ownership. 🏠