DollarChills
DollarChills

Reputation: 1086

Rails export to csv through associations

I have an issue with associations and download via csv export.

My export works if data is present in the sales association, but if there is no data my export remains blank. Removing the i.sales.each do part will export i.item_name and i.item_number fields fine.

So, if there is no data in my association my export remains blank. Is there a method to check if an association has information? I'm looking to include blank fields if no data is present.

I've tried i.try(:sales).each do |sale| to no avail.

CSV.generate(headers: true) do |csv|
  csv << attributes
  all.each do |i|
    i.sales.each do |sale|
      csv << [
          i.item_name,
          i.item_number,
          sale.try(:sale_cost)
      ]
     end
   end
 end

Upvotes: 2

Views: 729

Answers (4)

rogercampos
rogercampos

Reputation: 1724

What @Sascha Mayr says is the normal way to go. Think about the data you want to present in that CSV. How would you call each one of those rows? Now it's a sale, no? But your source model is an item. If a new association were to be added, like "favs", how would you call then each row?

I want to illustrate that the nature of the data to present doesn't correctly fit in a CSV file (2 dimensions) if you start adding info from more associations. Something else should be done then, different CSV files, or grouping by some other concept.

Upvotes: 0

Deepak Mahakale
Deepak Mahakale

Reputation: 23671

You need to use left join to get all the records from the first table. This will give you NULL values for the associated table, just as you want.

NOTE: Please change the references of Product model/table with the appropriate one.

Rails 5 and above

left_joins(:sales).select('products.*, sales.sale_cost').each do |product|
  csv << [
    product.item_name,
    product.item_number,
    (product.sale_cost || 'N/A')
  ]
end

Rails 4 and below

Product.joins("left join sales on products.id = sales.product_id")
       .select('products.*, sales.sale_cost')
       .each do |product|

  csv << [
    product.item_name,
    product.item_number,
    (product.sale_cost || 'N/A')
  ]
end

This will result in something like:

pencil,12345,20
pencil,12345,10 
eraser,11223,5
box,11333,N/A

Upvotes: 4

Sovalina
Sovalina

Reputation: 5609

Why not query your sales by association id ?
Assuming your i is for an Item model name, you can do something like:

all.each do |i|
  Sale.where(item_id: i.id).each do |sale|
    csv << [
      i.item_name,
      i.item_number,
      sale.try(:sale_cost)
    ]
  end
end

or select just the records where sales are present:

joins(:sales).group('items.id').each do |i|
  i.sales.each do |sale|
    csv << [
      i.item_name,
      i.item_number,
      sale.try(:sale_cost)
    ]
  end
end

Upvotes: 0

Sascha Mayr
Sascha Mayr

Reputation: 341

Try the following code

CSV.generate(headers: true) do |csv|
  csv << attributes
  all.each do |i|
    if i.sales.present?
     i.sales.each do |sale|
       csv << [
           i.item_name,
           i.item_number,
           sale.try(:sale_cost)
       ]
      end
    else
     csv << [
       i.item_name,
       i.item_number
     ]
    end
   end
 end

Upvotes: 0

Related Questions