Reading Image url via CSV upload in Rails - ruby-on-rails

I'm trying to upload a CSV file that has an image URL as one of the fields. I'm using paperclip to process images in my Rails 4 app. Here is the import code in my model. Can you tell me what's wrong with the below syntax - specifically the URI parsing code? If I remove the image field from my CSV file, everything uploads correctly.
I want rails to get the jpg file from the url and save it on our server. It's an ecommerce app so I'm trying to load product images for each product.
require 'csv'
require 'open-uri'
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
listing_hash = {:name => row['Name'], :description => row['Description'],
:price => row['Price'], :image => URI.parse.row['Image'] }
listing = Listing.where(id: listing_hash["id"])
if listing.count == 1
listing.first.update_attributes(listing_hash)
else
Listing.create!(listing_hash)
end # end if !product.nil?
end # end CSV.foreach
end # end self.import(file)

This part is wrong:
:image => URI.parse.row['Image']
You should be passing row['Image'] to the parse method like this:
URI.parse(row['Image'])

Related

Rails CSV upload to update records - attribute not saved to db

I have a system for updating InventoryItem records using a CSV upload.
I have this controller method:
def import
InventoryItem.import(params[:file], params[:store_id])
redirect_to vendors_dashboard_path, notice: "Inventory Imported."
end
Which of course calls this model method:
def self.import(file, store_id)
CSV.foreach(file.path, headers: true) do |row|
inventory_item = InventoryItem.find_or_initialize_by_code_and_store_id(row[0], store_id)
inventory_item.update_attributes(:price => row.to_hash.slice(:price))
end
end
I want to update only the :price attribute in the update because and :code and :store_id won't change. Currently the records being imported have price all as 0.0 (big decimal). Not nil, or the correct value, but 0.0, so clearly I'm doing something wrong to make this work. I know when I do this in the console it looks something like this:
inventory_item = InventoryItem.find_by_id(1)
inventory_item.update_attributes(:price => 29.99)
Any ideas on why I'm not updating the price attribute correctly?
Trying this, it doesn't seem like csv returns symbolized hash keys
and slice doesn't seem to work there. how about this inside your
CSV.foreach loop:
inventory_item.update_attributes(:price => row.to_hash["price"])

Mr. Ruby, Ms Rails, my json created record is empty

this newbie here is smacking his head with webservices over Rails.
Perhaps someone could ease my pain?
I've created a simple rails app, and generated the scaffold MyRecords. Then I'm trying to create a record over irb with the code below :
testWS.rb
require 'HTTParty'
class MyRecordCreate
include HTTParty
base_uri 'localhost:3000'
def initialize(u, p)
#auth = {:username => u, :password => p}
end
def post(text)
options = { :body => { name:text} }
self.class.post('/my_records', options)
end
end
response = HTTParty.get("http://localhost:3000/my_records/new.json")
print response
record = MyRecordCreate.new("","").post("test remote record")
print record
With the code above, I managed to create a record. the thing is that my Record (which only has the column "name") is created with an empty name!
Any suggestions on this one?
I'm longing to slice this despair piece by piece.
Thank you for your contribute.
Try adding these two lines to your HTTParty class:
format :json
headers "Accept" => "application/json"
These tell httparty and the remote service to which it connects to send and receive JSON. For your example (with .json at the end of the URL) it isn't necessary to add the second line, but I find it is good practice and keep it anyway.
The next problem is that Rails expects your uploaded data to be inside the top level name of your object. So, for your example, the options line should look something like:
options = { :body => { :person => { :name => text } } }
Replace person with the name of the model that you are attempting to create.

Rails: upload cvs file to process it as a hash

I have this model:
class Survey < ActiveRecord::Base
attr_accessor :csvFile_file_name
has_attached_file :csvFile, :path => ":rails_root/public/:class/:attachment/:id/:style_:basename.:extension"
serialize :content, Hash
#after_save :do_cvs_process
def do_csv_process
product = {}
FasterCSV.foreach(self.csvFile.path, :headers => true, :col_sep => ",") do |row|
row.to_hash.each do |key, value|
product[key.underscore.to_sym] = value
end
end
self.update_column(:content, {:first => product})
end
end
I have several problems:
Because of standard browser security, I have to upload file and save it before processing it with csv to assign it as a hash to my :content attribute... That's why I'm using update_column to avoid callbacks. Is there a clever way to do it?
It does not work! When back to the view <%= #survey.content %> rails tells me that it found an array when it expected a hash.
def self.import_csv_file(iFileName)
c = CSV.open iFileName
header= c.first.map{ |i| i.to_s.strip.downcase; }
c.each { |row| import_hash( Hash[*header.zip(row).flatten] ); }
c.close
end
My product class has an import_hash method that looks for lowercase/spacefree headers and matches them to fields in the product.
product.name = hash['productname'] || hash['name'] #for example.
use faster_csv gem. Here are some quick links:
[SOURCE] https://github.com/JEG2/faster_csv
[DOCS] http://fastercsv.rubyforge.org/
[CHEATSHEET]http://cheat.errtheblog.com/s/faster_csv/
Please do some R&D on GitHub before pasting a questions, these questions are already there.

Rails create two associatiated models in one New-Create action

I have such models:
class Doc
has_many :photos
end
and
class Photo
belongs_to :doc
end
all photos uploaded to the cloud with CarrierWave-Paperclip like approach.
DocController#new prebuilds Doc with:
#doc = Doc.new
And only after saving this new Doc, in update action i can really upload photos to existed Doc object with:
#doc.photos << some_new_photo
But i want this feature in doc#new action. So, how i can upload photos like prebuilded Photo objects and add them to prebuilded Doc with #doc.photos << [photos] at the same time?
UPD:
Main problem, that when i make doc#new - i don't really know how many photos i'll upload during using form. So i have dynamically builded array of photos, that shouldn't be saved to DB, if associated Doc not saved/
You can use a somewhat convoluted Rails feature called accepts_nested_attributes which lets you create any number of associated objects in one go.
Basically your create call would end up accepting something like this:
{ :doc => { :name => 'somname', :date => Time.now, :photos_attributes => [
{ :filename => 'funnybear.gif', :filesize => '120kb' },
{ :filename => 'happybear.gif', :filesize => '72kb' },
{ :filename => 'angrybear.gif', :filesize => '240kb' }
]}}
You can use blocks
#doc = Doc.new do |doc|
doc.photos << some_new_photo
end
or you can redefine initialize method
class Doc
def initialize
#photos << some_new_photos
end
end
Or you can use build:
#doc = Doc.new
params[:photos].each do |some_new_photo|
#doc.photos.build some_new_photo
end
if #doc.save!
... etc

Trouble importing csv file with ruby CSV Module

I'm trying to use Ruby's csv module to import the records contained in a csv file to my local table in a Ruby on Rails 3 application.
The table was created through the creation of model Movie.
Here is what I've been executing in console:
require 'csv'
CSV.foreach('public/uploads/VideoTitles2.csv') do |row|
record = Movie.new(
:media_format => row[0],
:title => row[1],
:copies_at_home => row[2],
:order => row[3]
)
record.save
end
The rows of the csv file match (in data type) the columns they're being passed into. Here is a shortened version of the csv file (VideoTitles2.csv) I'm attempting to import:
"DVD","LEAP OF FAITH",1,1
"DVD","COCOON",1,2
"DVD","TITANIC",1,3
where each record is separated by \n I believe. This csv file was exported from Access and its original file extension was .txt. I've manually changed it to .csv for sake of the import.
The problem is that, after executing the above lines in rails console, I get the following output:
=> nil
The import doesn't seem to happen. If anyone has an idea as to how I could remedy this I'd really appreciate it.
I don't see the problem. This code snippet returns nil because CSV.foreach returns nil, but this is no indication if the loop is run or not. Did you checked if any Movie was created? did you include any debug lines to follow the process?
You may want to check the output of record.save (or call record.save!), maybe validations errors are preventing the record from being created. Also, if you want the loop to return the created records, you can write this (Ruby >= 1.8.7):
require 'csv'
records = CSV.foreach('public/uploads/VideoTitles2.csv').map do |media_format, title, copies_at_home, order|
Movie.create!({
media_format: media_format,
title: title,
copies_at_home: copies_at_home,
order: order,
})
end
Okay there were two things I had wrong:
The exported csv file should not have quotations around the strings - I just removed them.
Thanks to tokland, the record.save! was necessary (as opposed to the record.save I was doing) - validation errors were preventing the records from being created.
So to conclude, one could just create the following function after creating the model/table Movie:
class Movie < ActiveRecord::Base
attr_accessible :media_format, :title, :copies_at_home, :order
require 'csv'
def self.import_movies()
CSV.foreach('public/uploads/movies.csv') do |row|
record = Movie.new(
:media_format => row[0],
:title => row[1],
:copies_at_home => row[2],
:order => row[3]
)
record.save!
end
end
end
Where movies.csv looks like the following:
Blu-ray, Movie 1, 1, 1
DVD, Movie 2, 1, 2
Blu-ray, Movie 3, 1, 3
then call this function in console as such:
Movie.import_movies()
and, as expected, all that would be returned in the console would be:
=> nil
Check your index view (if you've created one) and you should see that the records were successfully imported into the movies table.

Resources