Reputation: 847
I've been following this Railscast on CSV/Excel Export but I'm having a bit of an issue with the association logic.
CSV Confusion/Issue
In my Collection Model
I have
class Collection < ApplicationRecord
belongs_to :user
has_many :card_collections
has_many :cards, through: :card_collections
def self.to_csv
attributes = %w{name}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |collection|
csv << attributes.map{ |attr| collection.send(attr) }
end
end
end
# validates :user_id, presence: true
end
CSV Export
name
Demo 2
HEHHEHEEHHE
name is the column name Demo 2 is the first Collection HEHHEHEEHHE is the second Collection
I need far more information, but once I get 'one' parameter I can go from there. But this isn't working.'name' will return the name of ALL collections, which isn't quite what I want at all, but I'm also trying to get information about the 'cards' in the collection (Referenced by cards_collection)
To give you an example - In console I would type:
c = Collection.last
c.cards.first.name
and I would get the first cards name.
I'm unsure if I should be making this self.to_csv function in the Card_collections
controller, the Cards
controller or what. I'm found a lot of similar questions regarding CSV through associations but nothing that has led me to a solution
Excel Confusion
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Worksheet ss:Name="Card Collection">
<Table>
<Row>
<Cell><Data ss:Type="String">Name</Data></Cell>
<Cell><Data ss:Type="String">Text</Data></Cell>
<Cell><Data ss:Type="String">Set</Data></Cell>
</Row>
<% @collection.card_collections.each do |collection| %>
<Row>
<Cell><Data ss:Type="String"><%= collection.card.name %></Data></Cell>
<Cell><Data ss:Type="String"><%= collection.card.text %></Data></Cell>
<Cell><Data ss:Type="String"><%= collection.card.set %></Data></Cell>
</Row>
<% end %>
</Table>
</Worksheet>
</Workbook>
Is a sample script - I actually have this wrapped in an 'each' because if they choose Excel I'll allow them to get one sheet per 'collection'.
To give you an idea of the relation, my Collection View
looks like -
<p id="notice"><%= notice %></p>
<div class="center"><%= @collection.name %></div><br />
<div class="center">Made By:
<strong>
<% if @collection.public %>
<%= link_to @collection.user.name, {:controller => "users", :action => "show", :id => @collection.user.id} %><br />
<% else %>
Anonymous<br />
<% end %>
</strong>
Total Cards: <%= @collection.card_collections.sum(:card_counts) %>
Distinct Cards: <%= @collection.card_collections.count %> <br />
</div>
<% @collection.card_collections.in_groups_of(3, false).each do |group| %>
<div class='row'>
<% group.each do |card| %>
<div class='col-sm-6 col-md-4'>
<%= image_tag(card.card.image_url, class: "img-responsive") %>
<h3>
<%= link_to card.card.name, {:controller => "cards", :action => "show", :id => card.card.id }%>
</h3>
<div><%= card_text_swap(card.card.text) %></div>
<div><span class='cardLabel'>Set</span>: <i class="ss ss-<%= card.card.set.downcase %> ss-3x ss-<%= card.card.rarity.downcase %>"></i>
<span class="setName"><%= card.card.setName %></span>
</div>
<div>Total in Collection: <%= card.card_counts %></div>
</div>
<% end %>
</div>
<% end %>
<%= link_to 'Edit', edit_collection_path(@collection) %> |
<%= link_to 'Back', collections_path %>
I struggled in making the view originally but finally got it working, and I'm trying to use the same logic in the Excel export, but it's not rendering properly. (Immediate nil errors, so I think this might be a failure on my part.)
Additional Info All of this is stored within ActiveDirectory, and being rendered to a view currently. Unsure what other information I should offer.
New Excel Issue
Collections_Controller
def show
@collection = Collection.find(params[:id])
respond_to do |format|
format.html
format.csv { render text: @collection.to_csv }
format.xls { send_data @collection.to_csv(col_sep: "\t") }
end
end
View
<%= link_to "CSV", collection_path(format: "csv") %> |
<%= link_to "Excel", collection_path(format: "xls") %>
CSV is now working - Excel is not.
Error Provided:
ArgumentError in CollectionsController#show
wrong number of arguments (given 1, expected 0)
Upvotes: 0
Views: 1222
Reputation: 378
"def self.to_csv" defines a class method. If you want to list cards for given Collection you need to define and call (in show method of your collections controller) an instance method.
So I changed your to_csv in the following way:
def to_csv
attributes = %w{name}
CSV.generate(headers: true) do |csv|
csv << attributes
cards.each do |card|
csv << attributes.map{ |attr| card.send(attr) }
end
end
end
This is how to call to_csv in your controller:
class CollectionsController < ApplicationController
def show
@collection = Collection.find(params[:id])
respond_to do |format|
format.html
format.csv { render text: @collection.to_csv }
end
end
end
for Excel:
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Worksheet ss:Name="Card Collection">
<Table>
<Row>
<Cell><Data ss:Type="String">Name</Data></Cell>
<Cell><Data ss:Type="String">Text</Data></Cell>
<Cell><Data ss:Type="String">Set</Data></Cell>
</Row>
<% @collection.cards.each do |card| %>
<Row>
<Cell><Data ss:Type="String"><%= card.name %></Data></Cell>
<Cell><Data ss:Type="String"><%= card.text %></Data></Cell>
<Cell><Data ss:Type="String"><%= card.set %></Data></Cell>
</Row>
<% end %>
</Table>
</Worksheet>
</Workbook>
And generally when you want to access cards for given @collection just use cards
relation and you will not need extra .card
when you access attributes of given card.
Upvotes: 2