I'm trying to load my csv file to my rails database using postgresql engine.However, it returns an empty array when I test with postman to GET the data from my database.
My ruby code implemented in my lib directory:
require 'csv'
CSV.foreach('lib/seeds/glints.csv', headers: true, encoding: 'ISO-8859-1', col_sep: ';') do |row|
new_empty_aaray = []
new_empty_aaray << row.to_h
puts new_empty_aaray
end
puts "There are now #{AllRestaurant.count} rows in the all_restaurants table"
I then run rails db:seed to seed the data to database
my controller:
class AllRestaurantsController < ApplicationController
before_action :find_all_restaurant, only: [:show]
def index
#all_restaurants = AllRestaurant.all
render json: #all_restaurants
end
def show
render json: #all_restaurant
end
private
def find_all_resstaurant
#all_restaurant = AllRestaurant.find(params[:id])
end
end
path to the csv file in the lib folder lib/seeds/glints.csv
I really don't know what I'm missing
Related
I'm making an export to csv file functionality in a Ruby on Rails repo and I'm almost done. However, when I press the "Export all" button, I get the undefined method `export' for nil:NilClass error. The log shows that format.csv { send_data #foos.export, filename: "foos-#{Date.today}.csv" } went wrong. What am I missing please?
This is model
class Foo < ApplicationRecord
has_many :bars
def export
[id, name, foos.map(&:name).join(' ')]
end
end
This is part of controller
def index
#foos = Foo.all
end
def export
all = Foo.all
attributes = %w{name}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |foo|
csv << attributes.map{ |attr| foo.send(attr) }
end
respond_to do |format|
format.csv { send_data #foos.export, filename: "foos-#{Date.today}.csv" }
end
end
end
def name
"#{foo_id} #{name}"
end
This is View
<button class="btn btn-success">export all</button>
This is Routes
Rails.application.routes.draw do
resources :foos
get :export, controller: :foos
root "foos#index"
end
This is Rake (lib/tasks/export.rb)
namespace :export do
task foo: :environment do
file_name = 'exported_foo.csv'
csv_data = Foo.to_csv
File.write(file_name, csv_data)
end
end
Start by creating a service object that takes a collection of records and returns CSV so that you can test the CSV generation in isolation:
# app/services/foo_export_service.rb
# Just a Plain Old Ruby Object that converts a collection of foos into CSV
class FooExportService
# The initializer gives us a good place to setup our service
# #param [Enumerable] foo - an array or collection of records
def initialize(foos)
#headers = %w{name} # the attributes you want to use
#foos = foos
end
# performs the actual work
# #return [String]
def perform
CSV.generate do |csv|
#foos.each do |foo|
csv << foo.serializable_hash.slice(#headers).values
end
end
end
# A convenient factory method which makes stubbing the
# service easier
# #param [Enumerable] foos - an array or collection of records
# #return [String]
def self.perform(foos)
new(foos).perform
end
end
# example usage
FooExportService.perform(Foo.all)
Not everything in a Rails application needs to be jammed into a model, view or controller. They already have enough responsiblities. This also lets you resuse the code for example in your rake task if you actually need it.
This simply iterates over the collection and uses Rails built in serialization features to turn the model instances into hashes that can be serialized as CSV. It also uses the fact that Hash#slice also reorders the hash keys.
In your controller you then just use the service object:
class FoosController
def export
#foos = Foo.all
respond_to do |format|
format.csv do
send_data FooExportService.perform(#foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
You don't even really need a separate export action in the first place. Just use MimeResponds to add CSV as an availble response format to the index:
class FoosController
def index
# GET /foos
# GET /foos.csv
#foos = Foo.all
respond_to do |format|
format.html
format.csv do
send_data FooExportService.perform(#foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
<%= link_to("Export as CSV", foos_path(format: :csv)) %>
I am working on to allow download an excel file with the below code:
login = Etc.getlogin
#dataFile = "C:/rails/#{login}data.csv"
csv1=CSV.open(#dataFile, 'w') do |csv|
$data.each do |eachrow|
csv << [eachrow.name+"#gmail.com"]
end
end
send_file(#dataFile, :filename => "#{login}data", :type => "application/csv")
Using the above code, I am able to create a file and write the data.
Instead of this, how do i write the data in csv and get downloaded into users machine instead of saving in local/server.
What you can do is generate a string with the CSV library, using CSV::generate instead of CSV::open.
Controller:
class DataController < ApplicationController
def download
respond_to do |format|
format.csv { send_csv_download }
end
end
private
def send_csv_download
string = CSV.generate do |csv|
#data.each { |row| csv << ["#{row.name}#gmail.com"] }
end
send_data string, filename: 'foo.csv', type: :csv
end
end
config/routes.rb:
get '/download', to: 'data#download'
View:
<%= link_to 'Download CSV', download_path(format: :csv) %>
Note: Obviously, I have no idea where you get your #data from, since it isn't specified in your question.
So I have the controller who scrapes the entire html of a page and stores it into mysql database. Before I store the data I want to encode it using the htmlentities gem. My issue is that with some websites it works ok e.g https://www.lookagain.co.uk/ but with others I get invalid byte sequence in UTF-8 such as https://www.google.co.uk/ and I do not know why. At first I though it might be something wrong with the database so I have changed all the fields to LONGTEXT but the problem still persists
Controller:
class PageScraperController < ApplicationController
require 'nokogiri'
require 'open-uri'
require 'diffy'
require 'htmlentities'
def scrape
#url = watched_link_params[:url].to_s
puts "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOG#{#url}"
#page = Nokogiri::HTML(open(#url))
coder = HTMLEntities.new
#encodedHTML = coder.encode(#page)
create
end
def index
#savedHTML = ScrapedPage.all
end
def show
#savedHTML = ScrapedPage.find(id)
end
def new
#savedHTML = ScrapedPage.new
end
def create
#savedHTML = ScrapedPage.create(domain: #url, html: #encodedHTML, css: '', javascript: '')
if #savedHTML.save
puts "ADDED TO THE DATABASE"
redirect_to(root_path)
else
puts "FAILED TO ADD TO THE DATABASE"
end
end
def edit
end
def upadate
end
def delete
#watched_links = ScrapedPage.find(params[:id])
end
def destroy
#watched_links = ScrapedPage.find(params[:id])
#watched_links.destroy
redirect_to(root_path)
end
def watched_link_params
params.require(:default).permit(:url)
end
end
After setting up the apache server When we choose the .csv file to be imported I get the following error message:
TypeError in ProductImportsController#create:
no implicit conversion of ActiveSupport::HashWithIndifferentAccess into String
My product_imports_controller.rb:
require 'csv'
class ProductImportsController < ApplicationController
def new
#product_import = ProductImport.new
end
def create
csv_text = File.read(params[:product_import])
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
ProductImport.create!(row.to_hash)
end
end
end
Try this:
The issue is that there is a security aspect with hashes in Controllers.
You try row.to_hash.permit! but i'll doubt that it will work
Create it in the model:
require 'csv'
class ProductImportsController < ApplicationController
def new
#product_import = ProductImport.new
end
def create
csv_text = File.read(params[:product_import])
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
ProductImport.create_from_csv(row.to_hash)
end
end
end
class ProductImport < ActiveRecord::Base
def self.create_from_csv(data)
self.create!(data)
end
end
I am trying to export some data to CSV in Rails 4. I have two models: Excursions and Inscriptions. One excursion has many inscriptions and one inscription belongs to one excursion.
I have my nested routes defined this way:
resources :excursions do
resources :inscriptions
get 'exportcsv' => 'excursions#download'
end
So the behavior I am trying to achieve is: when I visit the route /excursions/1/exportcsv, a CSV will be downloaded to my computer and it will contain all the inscriptions with excursion_id = 1 in CSV format.
In my excursion model I have defined self.to_csv:
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
self.inscriptions.each do |inscription|
csv << inscription.attributes.values_at(*column_names)
end
end
end
And my excursion controller's method download:
def download
#excursion = Excursion.find(params[:id])
respond_to do |format|
format.html
format.csv { send_data #excursion.to_csv }
end
end
EDIT: When I go to a route like: /excursions/:id/exportcsv the server is throwing an ActiveRecord::RecordNotFound error. This error is easy to solve, but if I solve the RecordNotFound I get an ActionController::UnknownFormat in this line:
def download
#excursion = Excursion.find(params[:id])
respond_to do |format| ########THIS LINE
format.html
format.csv { send_data #excursion.to_csv }
end
end
What I am doing wrong? Maybe all this approach is not correct...
I would update the routes to the following:
resources :excursions do
get 'download', on: :member, constraints: { format: /(html|csv)/ }
resources :inscriptions
end
Also there is a bug in your model code. You are exporting inscriptions but are using Excursion column_names instead of Inscription column_names. Following is the updated model code.
class Excursion < ActiveRecord::Base
def to_csv(options = {})
CSV.generate(options) do |csv|
inscription_column_names = Inscription.column_names
csv << inscription_column_names
self.inscriptions.each do |inscription|
csv << inscription.attributes.values_at(*inscription_column_names)
end
end
end
Now try to access http://localhost:3000/excursions/:id/download.csv
Replace :id with an existing Excursion records id. If you still encounter ActiveRecord::RecordNotFound error, then the problem could be that you are trying to access an Excursion that doesn't actually exist in the database.