title: Rails Export multiple tables to csv
body: <p>Hi I have a simple rails application that has two models Equipment_Types &amp; Tasks</p>
  
  <p>Each equipment type has many tasks. When I export to csv file I would like to export the name of the equipment type, the task name and the associated schedule. Basically every thing that is displayed on equipment_type/show.html.erb</p>
  
  <pre><code>&lt;p id="notice"&gt;&lt;%= notice %&gt;&lt;/p&gt;
  &lt;div class="row"&gt;
    &lt;table class="table table-bordered"&gt;
    &lt;thead&gt;
    &lt;tr&gt;
      &lt;th class="align-middle" rowspan="2"&gt;Equipment&lt;/th&gt;
      &lt;th class="align-middle" rowspan="2"&gt;Task&lt;/th&gt;
      &lt;th class="text-center" colspan="4"&gt;Frequency&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th class="text-center"&gt;M&lt;/th&gt;
      &lt;th class="text-center"&gt;Q&lt;/th&gt;
      &lt;th class="text-center"&gt;B&lt;/th&gt;
      &lt;th class="text-center"&gt;A&lt;/th&gt;
    &lt;/tr&gt;
    &lt;/thead&gt;
  
    &lt;tbody&gt;
    &lt;tr&gt;
      &lt;% if @taskcount &gt; 3 %&gt;
      &lt;td class="text-center bottomtotop" rowspan="0"&gt;&lt;%= link_to @equipment_type.name, edit_equipment_type_path(@equipment_type) %&gt;&lt;/td&gt;
        &lt;% else %&gt;
        &lt;td class="text-center" rowspan="0"&gt;&lt;%= link_to @equipment_type.name, edit_equipment_type_path(@equipment_type) %&gt;&lt;/td&gt;
      &lt;% end %&gt;
    &lt;/tr&gt;
      &lt;% @equip_tasks.each do |task| %&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;%= link_to task.name, task %&gt;&lt;/td&gt;
        &lt;td class="text-center"&gt;&lt;%= if task.monthly then 'x' else ' ' end %&gt;&lt;/td&gt;
        &lt;td class="text-center"&gt;&lt;%= if task.quarterly then 'x' else ' ' end %&gt;&lt;/td&gt;
        &lt;td class="text-center"&gt;&lt;%= if task.sixmonthly then 'x' else ' ' end %&gt;&lt;/td&gt;
        &lt;td class="text-center"&gt;&lt;%= if task.annually then 'x' else ' ' end %&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;% end %&gt;
    &lt;div class="collapse" id="collapsenewline"&gt;
  
    &lt;/div&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
  &lt;/div&gt;
  &lt;div class="row"&gt;
    &lt;div class="col-sm"&gt;
      &lt;%= link_to 'Add Task', new_task_path(@equipment_type), class: 'btn btn-dark' %&gt;
    &lt;/div&gt;
    &lt;div class="col-sm"&gt;
      &lt;%= link_to 'Back', equipment_types_path, class: 'btn btn-dark' %&gt;
    &lt;/div&gt;
    &lt;div class="col-sm"&gt;
      &lt;button class="btn btn-dark" type="button" data-toggle="collapse" data-target="#collapsedownload" aria-expanded="false" aria-controls="collapseExample"&gt;
        Download
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="row"&gt;
    &lt;div class="col-sm"&gt;
    &lt;/div&gt;
    &lt;div class="col-sm"&gt;
    &lt;/div&gt;
    &lt;div class="col-sm"&gt;
      &lt;div class="collapse" id="collapsedownload"&gt;
        &lt;div class="card card-body"&gt;
          &lt;h3&gt;Download File&lt;/h3&gt;
          &lt;%= link_to "csv", equipment_types_path(format: "csv"), class: 'btn btn-dark' %&gt;
          &lt;br&gt;
          &lt;%= link_to "pdf", equipment_types_path(format: "pdf"), class: 'btn btn-dark' %&gt;
          &lt;br&gt;
          &lt;%= link_to "word", equipment_types_path(format: "word"), class: 'btn btn-dark' %&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>equipment_type Model</p>
  
  <pre><code>class EquipmentType &lt; ApplicationRecord
    has_many :tasks
    accepts_nested_attributes_for :tasks
  
    def self.import(file)
      CSV.foreach(file.path, headers: true) do |row|
        EquipmentType.create! row.to_hash
      end
    end
  
    def self.to_csv
      CSV.generate do |csv|
        csv &lt;&lt; column_names
        all.each do |equipmenttype|
          csv &lt;&lt; equipmenttype.attributes.values_at(*column_names)
        end
      end
    end
  end
  </code></pre>
  
  <p>equipment_types Controller</p>
  
  <pre><code>class EquipmentTypesController &lt; ApplicationController
    before_action :set_equipment_type, only: [:show, :edit, :update, :destroy]
    before_action :set_task, only: [:show]
  
    # GET /equipment_types
    # GET /equipment_types.json
    def index
      @equipment_types = EquipmentType.all
  
      respond_to do |format|
        format.html
        format.csv { send_data @equipment_types.to_csv }
      end
    end
  
  
    # GET /equipment_types/1
    # GET /equipment_types/1.json
    def show
      @equipment_type = EquipmentType.find_by(id: params[:id])
      @tasks = Task.all
      @equip_tasks = @equipment_type.tasks.all
      @taskcount = @equip_tasks.count
  
  
      respond_to do |format|
        format.html
        format.csv { send_data text: @equip_tasks.to_csv }
      end
    end
  
    # GET /equipment_types/new
    def new
      @equipment_type = EquipmentType.new
    end
  
    # GET /equipment_types/1/edit
    def edit
    end
  
    # POST /equipment_types
    # POST /equipment_types.json
    def create
      @equipment_type = EquipmentType.new(equipment_type_params)
  
      respond_to do |format|
        if @equipment_type.save
          format.html { redirect_to @equipment_type, notice: 'Equipment type was successfully created.' }
          format.json { render :show, status: :created, location: @equipment_type }
        else
          format.html { render :new }
          format.json { render json: @equipment_type.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # PATCH/PUT /equipment_types/1
    # PATCH/PUT /equipment_types/1.json
    def update
      respond_to do |format|
        if @equipment_type.update(equipment_type_params)
          format.html { redirect_to @equipment_type, notice: 'Equipment type was successfully updated.' }
          format.json { render :show, status: :ok, location: @equipment_type }
        else
          format.html { render :edit }
          format.json { render json: @equipment_type.errors, status: :unprocessable_entity }
        end
      end
    end
  
    def import
      EquipmentType.import(params[:file])
      redirect_to equipment_type_path, notice: "Equipment Type Added Successfully"
    end
  
    # DELETE /equipment_types/1
    # DELETE /equipment_types/1.json
    def destroy
      @equipment_type.destroy
      respond_to do |format|
        format.html { redirect_to equipment_types_url, notice: 'Equipment type was successfully destroyed.' }
        format.json { head :no_content }
      end
    end
  
    private
      # Use callbacks to share common setup or constraints between actions.
      def set_equipment_type
        @equipment_type = EquipmentType.find(params[:id])
      end
  
      def set_task
        @task = Task.find(params[:id])
      end
  
      # Never trust parameters from the scary internet, only allow the white list through.
      def equipment_type_params
        params.require(:equipment_type).permit(:name, task: [])
      end
  end
  </code></pre>
  
  <p>Task Model</p>
  
  <pre><code>class Task &lt; ApplicationRecord
    belongs_to :equipment_type
  end
  </code></pre>
  
  <p>Tasks Controller</p>
  
  <pre><code>class TasksController &lt; ApplicationController
    before_action :set_task, only: [:show, :edit, :update, :destroy]
  
    # GET /tasks
    # GET /tasks.json
    def index
      @tasks = Task.all
    end
  
    # GET /tasks/1
    # GET /tasks/1.json
    def show
    end
  
    # GET /tasks/new
    def new
      @task = Task.new
    end
  
    # GET /tasks/1/edit
    def edit
    end
  
    # POST /tasks
    # POST /tasks.json
    def create
      @task = Task.new(task_params)
  
      respond_to do |format|
        if @task.save
          format.html { redirect_to @task, notice: 'Task was successfully created.' }
          format.json { render :show, status: :created, location: @task }
        else
          format.html { render :new }
          format.json { render json: @task.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # PATCH/PUT /tasks/1
    # PATCH/PUT /tasks/1.json
    def update
      respond_to do |format|
        if @task.update(task_params)
          format.html { redirect_to @task, notice: 'Task was successfully updated.' }
          format.json { render :show, status: :ok, location: @task }
        else
          format.html { render :edit }
          format.json { render json: @task.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # DELETE /tasks/1
    # DELETE /tasks/1.json
    def destroy
      @task.destroy
      respond_to do |format|
        format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
        format.json { head :no_content }
      end
    end
  
    private
      # Use callbacks to share common setup or constraints between actions.
      def set_task
        @task = Task.find(params[:id])
      end
  
      # Never trust parameters from the scary internet, only allow the white list through.
      def task_params
        params.require(:task).permit(:name, :monthly, :quarterly, :sixmonthly, :annually, :equipment_type_id)
      end
  end
  </code></pre>