Home > OS >  How to get data from multiple tables and turn them with each in erb
How to get data from multiple tables and turn them with each in erb

Time:12-17

Want to achieve

ruby 2.6.5 rails 6.0.3

Thank you for your interest. I am creating a web application with rails.

I would like to know how to extract only the data of the columns I want from multiple tables, put them into an array, and then output them using each.

Details

I want to extract the relevant users.name, companies.company_name, and tasks.task_name from the following table and put them into an array as a single unit. I want to output the array we have created in this way, one at a time, using each in erb.

Like this

・john Acompany task3
・white Dcompany task12
・carl Bcompany task8
・mark Ccompany task97

tables

users table

id name sex company_id
1 john 1 1
2 white 1 4
3 carl 1 2
4 mark 1 3

companies table

id company_name industry_1 industry_2
1 Acompany 3 9
2 Bcompany 6 10
3 Ccompany 1 3
4 Dcompany 4 8

tasks table

id task_name company_id
1 task3 1
2 task12 4
3 task97 3
4 task8 2

Tried

I thought that I could pack each element into an array as shown below. But I couldn't imagine how to implement it, so I gave up.

user_name = []
users.each do |user|
  user_name << user.name
end 

CodePudding user response:

You can use the joins method from ActiveRecord and get the columns you're looking for with pluck:

user_details = User.joins(company: :tasks).pluck("users.name", "companies.company_name", "tasks.task_name")
#=> [["john", "Acompany", "task3"], ["white", "Dcompany", "task12"], ...]

Next, iterate over the array of arrays that was returned from the above code to display the data in the way you want. Keep in mind in that in your DB architecture a company has_many tasks so you may end up with several arrays for the same company if that company has more than one task.

user_details.each do |user_detail|
  puts "・ "   user_detail.join(" ")
end

Other (and preferred) solution based on comment from max :

User.includes(company: :tasks).each do |user|
 # Here you can retrieve and display the data you need using user.name, user.company.name, user.company.tasks
end

CodePudding user response:

This is not a good idea. By passing arrays from your controller to the view you're skipping the model layer completely and skipping all it provides in terms of desearialization and encapsulation (and more). Dealing with simple arrays also destroys the readability of the code:

# which one of these was what now?
<tr>
  <td><%= data[0] %></td>
  <td><%= data[1] %></td>
</tr>

It is after all a MVC framework built in an object oriented language. Your code should not look like that.

Instead you can either use eager loading and delegation:

class User < ApplicationRecord
  belongs_to :company
  delegate :name, to: :company, prefix: true
end
@users = User.eager_load(:company)
             .all
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Company</th>
    </tr>
  </thead>
  <tbody>
    <%= @users.each do |user| %>
    <tr>
      <td><%= user.name %></td>
      <td><%= user.company_name %></td>
      # ...
     </tr>
  </tbody>
<% end %>

In some cases you may want to use joins instead to just select a single column or an aggregate from the assocation through:

class UsersController
  def index
    @users = User.joins(:company)
                 .select(
                   'users.*', 'companies.name AS company_name'
                  )
  end
end

When it comes to tasks you have to figure out what it is that you want to actually display. Since the assocations is most likely many to many to both users and companies its not clear which task should even be listed. All of them? The first? The last?

  • Related