Convert a Hash into a CSV the easy way.
Add this line to your application's Gemfile:
gem 'csvision'
And then execute:
bundle
Or install it yourself as:
gem install csvision
CSVision has no prerequisites other than ruby itself, which is pretty cool just include the csvision
gem in your app and you'll be good to go.
CSVision adds to Hash
the to_csv
method, anything that inherits from Hash
will inherit this method as well, you do not need to open Hash
and include CSVision
in it, just require the library in your code.
require 'csvision'
sample = { :name => 'foo', :last_name => 'bar', :age => 10 }
sample.to_csv #=> "\"last_name\",\"name\",\"age\"\n\"bar\",\"foo\",\"10\""
CSVision adds the following methods to Rails:
to_csv
at the model instanceto_csv
at the model classadd_csvision
at the model class
A rails model might look something like this:
class Product < ActiveRecord::Base
validates_presence_of :name, :permalink, :description
add_csvision :except => %w/updated_at created_at/
end
CSVision lets you customize the way your CSV is formed, you can use any of the following options in the add_csvision
method:
:only
to set only those parameters you wish to include.:except
this does the opposite it excludes options from the list.:delimeter
this set the field delimeter and it defaults to"
:separator
this set the field separator and it defults to,
That's good and all but, you never want to just convert a single object to csv but collections instead, so imagine this model instead:
class User < ActiveRecord::Base
add_csvision :csv_headers => %w/street_cred nickname incognito/, :body => lambda { |u| [ u.street_cred, u.nickname, u.incognito ] }
scope :flunky, where( 'points <= 5' )
def incognito
nickname.reverse
end
def street_cred
points * 100 + ( nickname_cred )
end
private
def nickname_cred
nickname.unpack( 'U' * nickname.length ).sum # good nickname equals more street cred
end
end
You can use the :headers
option to set your header names, and the :body
option to specify the methods or properties from the option you want
called in your csv, this gives you flexibility to choose how your csv is formed and from what it is formed, so this is an example of how this works.
5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i * 5 ) }
puts User.to_csv
this will print:
"street_cred","nickname","incognito"
"495","user0","0resu"
"998","user3","3resu"
"1501","user6","6resu"
"2004","user9","9resu"
"2546","user12","21resu"
You can chain active record calls and even scopes in to your mix, so consider:
5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i *5 ) }
puts User.flunky.to_csv
will print:
"street_cred","nickname","incognito"
"495","user0","0resu"
"998","user3","3resu"
"1501","user6","6resu"
Lastly, with the exception of :except
and :only
which will be ignore because you're setting the body manually all other option work:
5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i *5 ) }
puts User.to_csv( :headers => false )
Will print:
"495","user0","0resu"
"998","user3","3resu"
"1501","user6","6resu"
"2004","user9","9resu"
"2546","user12","21resu"
Anything that inherits from Hash
will respond_to? :to_csv
however if you want to use this in any other regular class make sure you do the following:
- Create a
Hash
attribute namedattributes
. - You'll need to have class
count
andfind_each
methods if you want support for setting thebody
. include CSVision
in your class.
class SampleStack
include CSVision
attr_accessor :attributes
add_csvision :csv_headers => %w/price name/, :body => lambda { |s| [ s[:name], s[:price] ] }
def initialize( attributes={}, inventory = [] )
@attributes = attributes
@@inventory = inventory
end
def self.count
@@inventory.size
end
def self.find_each( opts={} )
@@inventory.each do |item|
yield item
end
end
end
After wards imagine the following:
sample_stack = SampleStack.new( :foo => 'foo', :bar => 'bar' )
puts sample_stack.to_csv
Will print:
"foo","bar"
"foo","bar"
But more importantly to_csv
at the class level will:
inventory = [ { :name => 'beer', :price => 9 }, { :name => 'milk', :price => 5 }, { :name => 'tuna', :price => 3 } ]
sample_stack = SampleStack.new({ :name => 'groceries'}, inventory)
puts SampleStack.to_csv
Prints:
"price","name"
"beer","9"
"milk","5"
"tuna","3"
- Add support for other ORM's
- Rails 3.x responder.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request