I'm following the tutorial http://www.funonrails.com/2012/01/csv-file-importexport-in-rails-3.html]for upload files in rails 3, because I need that my app's user could upload csv files but when I tried to save the file I get: uninitialized constant CustomersController::CSV message, before change my routes to get "customers/import" to post "customers/import" I had other error No route matches [POST] "/customers/import" what Im doing wrong? thanks in advance.
MY CONTROLLER:
class CustomersController < ApplicationController
def import
if request.post? && params[:file].present?
infile = params[:file].read
n, errs = 0, []
CSV.parse(infile) do |row|
n += 1
# SKIP: header i.e. first row OR blank row
next if n == 1 or row.join.blank?
# build_from_csv method will map customer attributes &
# build new customer record
customer = Customer.build_from_csv(row)
# Save upon valid
# otherwise collect error records to export
if customer.valid?
customer.save
else
errs << row
end
end
# Export Error file for later upload upon correction
if errs.any?
errFile ="errors_#{Date.today.strftime('%d%b%y')}.csv"
errs.insert(0, Customer.csv_header)
errCSV = CSV.generate do |csv|
errs.each {|row| csv << row}
end
send_data errCSV,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=#{errFile}.csv"
else
flash[:notice] = I18n.t('customer.import.success')
redirect_to import_url #GET
end
end
end
end
MY MODEL:
class Customer < ActiveRecord::Base
scope :active, where(:active => true)
scope :latest, order('created_at desc')
def self.csv_header
"First Name,Last Name,Email,Phone,Mobile, Address, FAX, City".split(',')
end
def self.build_from_csv(row)
# find existing customer from email or create new
cust = find_or_initialize_by_email(row[2])
cust.attributes ={:first_name => row[0],
:last_name => row[1],
:email => row[3],
:phone => row[4],
:mobile => row[5],
:address => row[6],
:fax => row[7],
:city => row[8]}
return cust
end
def to_csv
[first_name, last_name, email, phone, mobile, address, fax, city]
end
end
*MY VIEW:
<h1>Subir Archivos</h1>
<%= form_tag('import', :multipart => true) do %>
<p>
File:<br />
<%= file_field_tag 'file' %><br />
</p>
<p>
<%= submit_tag "subir" %>
</p>
<% end %>
MY ROUTES:
Pruebaupcsv::Application.routes.draw do
post "customers/import"
You need to add a require 'csv' before you use it, either in an initializer, or at the top of your controller.
Related
I am trying to upload a csv file with Rails from Active Admin.
I have a model User, which has columns name(string) and age(integer).
My csv file looks like this:
name,age
"Peter",31
"Susan",30
"John",40
Then I have in my admin/user.rb:
ActiveAdmin.register User do
permit_params :name, :age
collection_action :upload_csv do
render "admin/csv/upload_csv_user"
end
collection_action :import_csv_data_user, :method => :post do
ret_val = CsvDb.update_model_from_csv("user", params[:dump][:file])
redirect_to :action => :index, :notice => ret_val
end
end
And in my admin/csv/upload_csv_user.html.erb I have:
<%= form_for(:dump, :url=>{:action=>"import_csv_data_user"}, :html => { :multipart => true }) do |f| %>
<%= f.file_field :file %>
<%= f.submit "Submit", confirm: "Are You Sure?" %>
<% end %>
Inside a csv_db.rb file I have:
require 'csv'
module CsvDb
def self.update_model_from_csv(model_name, file)
csv_data = CSV.read(file.path)
columns = csv_data.shift
model = model_name.classify.constantize
ret_val = "Data updated successfully!"
begin
model.import columns, csv_data, on_duplicate_key_update: columns, validate: false
rescue Exception => e
ret_val = e
end
ret_val
end
end
When I try to upload the file I get the following error: Illegal quoting in line 1.
And below it's written:
part "\"name"
parse "\"name,age\""
parts ["\"name", "age\""]
unconverted nil
in_extended_col false
csv []
I checked lots of examples and I can't find the error. Maybe my csv file is formatted incorrectly.
require 'csv'
module CsvDb
def self.update_model_from_csv(model_name, file_params)
CSV.foreach(file_params.path, headers: true) do |row|
model = model_name.classify.constantize
begin
name = row["name"]
age = row["age"]
if model.create(name: name, age: age)
result = "Imported successfully!"
end
rescue Exception => e
result = e
end
end
result
end
end
Use this method in controller as: -
#pass model name and params[:file], which is csv uploaded from user end
CsvDb.update_model_from_csv(model_name, params[:file])
I'm trying to create a line graph of weights for a user off of the lazy high charts gem.
I currently have in my users_controller
def show
#user = User.find(params[:id])
#weights = Weight.where(user_id: #user.id)
#weight_hash = #weights.to_json
#chart = LazyHighCharts::HighChart.new('graph') do |f|
f.title(:text => "Historical Weights")
f.xAxis(:type => 'datetime', :title => {:text =>'Date'})
f.yAxis(:title => {:text => "pounds"})
f.series(:name => 'Weight', :data => #weight_hash)
f.chart({defaultSeriesType => 'line'})
end
end
Within my weight model I have:
class Weight < ActiveRecord::Base
belongs_to :user
def as_json(*args)
{
:weight => self.weight,
:date => self.date
}
end
end
Then in my users/show.html.erb I have
<%= high_chart("Weight", #chart) %>
but i'm getting the error
undefined local variable or method `defaultSeriesType' for
#
I'm not sure how this method should be declared as it is part of the gem. Could anyone please explain what is going on?
In this line:
f.chart({defaultSeriesType => 'line'})
It looks like you forgot to add a colon to defaultSeriesType to make it a symbol, so Ruby thinks it's a variable/method. Try changing it to:
f.chart({:defaultSeriesType => 'line'})
...like the other hashes.
I use Feedjira Gem (Rails) to fetch/grab the rss-feeds from several websites. Everything works fine, but the only that has bugged me long time is the source-feed (the website I grab the rss from).
I want to show users which website the rss comes from. Right now, I grab the whole url, but I want to only grab what is after www and before .com. Anyway I can get it work or I can grab the feed source from the rss file.
I see this in rss file, but can't grab it.
<channel>
<link>http://www.domain.com/</link>
And here is my whole model.
class FeedEntry < ActiveRecord::Base
acts_as_punchable
def self.update_from_feed(feed_url)
feed = Feedjira::Feed.fetch_and_parse(feed_url)
add_entries(feed.entries)
end
private
def self.add_entries(entries)
entries.each do |entry|
unless exists? :guid => entry.id
create!(
:name => entry.title,
:url => entry.url,
:guid => entry.id,
:source => entry.url,
:summary => entry.summary,
:published_at => entry.published,
)
end
end
end
end
Thanks in advance!
You can grab the source by
feed = Feedjira::Feed.fetch_and_parse(feed_url)
source = feed.url # -> http://www.domain.com/
To grab what is after www and before .com, you can do something like this
source = URI.parse(feed.url).host.split('.')[-2] # -> domain
Now, here we go
def self.update_from_feed(feed_url)
feed = Feedjira::Feed.fetch_and_parse(feed_url)
source = URI.parse(feed.url).host.split('.')[-2]
add_entries(feed.entries, source)
end
private
def self.add_entries(entries, source)
entries.each do |entry|
unless exists? :guid => entry.id
create!(
:name => entry.title,
:url => entry.url,
:guid => entry.id,
:source => source,
:summary => entry.summary,
:published_at => entry.published,
)
end
end
end
It would work!
Hello dear Programmers,
I'm trying to develop a web application with the ebook "Praxiswissen - Ruby on Rails". My problem is that I want to save Images through a form to my project directory. The database just saves the name of the pictures with the saving time:
def unique_and_proper_filename(filename)
Time.now.to_i.to_s + '_' + File.basename(filename)
end
My problem is that my pictures dont get saved after submitting my form. I dont get some exceptions, thats why I dont know where my issue is.
Controller:
class PostsController < ApplicationController
require 'will_paginate'
def new
#post = Post.new
end
# information about saving the picture
def create
#post = Post.new(params[:post].permit(:title, :description, :date, :image_file, :thumbnail_file))
# Form isn't correctly filled message
if !#post.valid?
flash.now[:notice] = "Bitte füllen Sie alle Felder aus und überprüfen Sie Ihre Angaben."
render(:action => :new)
# Files weren't saved message
elsif !#post.save_files
flash.now[:notice] = "Es trat ein Fehler beim Hochladen der Dateien auf."
render(:action => :new)
# Files saved correctly message
else
#post.save
flash[:notice] = "Dateien wurden hochgeladen und die Daten wurden gespeichert."
redirect_to(:action => :list)
end
end
# list action for listing my pictures
def list
#posts = Post.paginate(:page => params[:page], :order => "date DESC", :per_page => 15)
#post_pages = Post.paginate(:page => params[:page], :order => "date DESC", :per_page => 15)
end
end
HTML Form:
<h2>Neues Foto anlegen</h2>
<%= form_tag({:action => :create}, :multipart => true) %>
<h3>Bilddaten</h3>
<p>
Titel<br/>
<%= text_field(:post, :title) %>
</p>
<p>
Beschreibungen<br/>
<%= text_field(:post, :description) %>
</p>
<p>
Datum und Uhrzeit<br/>
<%= datetime_select(:post, :date, :order => [:day, :month, :year, :hour]) %>
</p>
<p>
<h3>Datei-Upload</h3>
<p>
Bilddatei:<br/>
<%= file_field(:post, :image_file) %>
</p>
<p>
Thumbnail:<br/>
<%= file_field(:post, :thumbnail_file) %>
</p>
<%= submit_tag("Speichern") %>
</p>
</form>
Model:
class Post < ActiveRecord::Base
validates_presence_of(:title, :description, :date, :image, :thumbnail)
I18n.enforce_available_locales = false
def image_file= (fileobj)
if fileobj.size > 0
#image_file = fileobj
self.image = unique_and_proper_filename(fileobj.original_filename)
end
end
def thumbnail_file= (fileobj)
if fileobj.size > 0
#thumbnail_file = fileobj
self.thumbnail = unique_and_proper_filename(fileobj.original_filename)
end
end
def save_files
# Bilddatei save
if !save_uploaded_file(#image_file, IMAGE_DIR, self.image)
return false
end
# Thumbnail save
if !save_uploaded_file(#thumbnail_file, THUMBNAIL_DIR, self.thumbnail)
return false
end
end
private
def unique_and_proper_filename(filename)
Time.now.to_i.to_s + "_" + File.basename(filename)
end
private
def save_uploaded_file(fileobj, filepath, filename)
# Complete Path
complete_path = Rails.root + "/public/" + filepath
# if neccessary, create directory
FileUtils.mkdir_p(complete_path) unless File.exists?(complete_path)
# save data
begin
f = File.open(complete_path + "/" + filename, "wb")
f.write(fileobj.read)
rescue
return false
ensure
f.close unless f.nil?
end
end
end
I'm only getting the message that there went something wrong with saving the files when i fill the form correctly but it should return a message that says that my file were saved.
I'm sorry for that massive length of my question but I really dont know where my issue is... If there's a need for more information or code, I will add it as fast as I can.
Thank you very much in advance!
Update 17/02/22:
Paperclip has since been deprecated, it is recommended you use Rails' own Active Storage.
Original Answer:
I'm sorry but I'll only be able to recommend what we use:
Paperclip
I appreciate you're using a tutorial, but I'd highly recommend using the Paperclip gem for this
This handles ALL the heavy lifting for you:
#GemFile
gem "paperclip", "~> 4.1.1"
Model
#app/models/post.rb
Class Post < ActiveRecord::Base
has_attached_file :image
end
#migration
add_attachment :posts, :image
Controller
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
end
private
def post_params
params.require(:post).permit(:image, :other, :params)
end
View
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.file_field :image %>
<% end %>
I'm lucky to tell that I found my issue. My save_files method in my Post model doesn't returned true..
I post this answer because maybe someone could use this question as an answer for his own problem. Here's where I added my return true :
def save_files
# Bilddatei save
if !save_uploaded_file(#image_file, IMAGE_DIR, self.image)
return false
end
# Thumbnail save
if !save_uploaded_file(#thumbnail_file, THUMBNAIL_DIR, self.thumbnail)
return false
end
return true # <--------- Need to be added!
end
Try to add enctype= multipart/formdata in your form tag if you are using form to post your data
I'm trying to implement a simple login system in Rails, but when I try to display the username of a logged in user, I get this error:
can't convert Symbol into Integer
Extracted source (around line #60):
57: </ul>
58: <% if session[:logged_in] %>
59: <% user = session[:user] %>
60: <p class="pull-right">Howdy, <strong><%= user[:username] %></strong>!</p>
61: <% end %>
62: </div>
63: </div>
My model code is here:
require 'digest'
class User < ActiveRecord::Base
before_save {|user| user.password = Digest::SHA1.hexdigest(user.password)}
attr_accessible :username, :password, :email
validates_length_of :username, :password, :minimum => 7
validates_presence_of :username,:password,:email, :on => :create
validates_format_of :email, :with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
end
This is how I set session[:user]:
def create
if User.find(:all, :conditions => {:username => params[:username], :password => Digest::SHA1.hexdigest(params[:username])})
user = User.find(:all, :conditions => {:username => params[:username], :password => Digest::SHA1.hexdigest(params[:password])})
session[:user] = user
session[:logged_in] = true
redirect_to(:root, :notice => "Thanks for logging in!")
else
redirect_to(:new, :notice => "You supplied an invalid username/password combination.")
end
end
Probably session[:user] is not a Hash, as you expect it to be, but an Array. Thus subscripting it with anything other than an integer is not valid.
How to fix this? Change the code that is actually setting the session variable (like session[:user] = XYZ).
EDIT: User.find(:all, ...) returns an array, so as I assumed, you are assigning an array to session[:user]. You should only assign the first user found (and in fact, there should be only one matching the criteria). Even better, you should only store the username in the session and fetch it from the database if needed:
def create
user = User.where(:username => params[:username], :password => Digest::SHA1.hexdigest(params[:username])).first
if user
session[:user_id] = user.id
else
redirect_to(:new, :notice => "You supplied an invalid username/password combination.")
end
end
Then in the action associated with your view:
def ...
#user = User.find(session[:user_id])
unless #user
# redirect to error page, user was deleted in the meantime
end
end
Then in the view:
<%= #user.username %>
Dumping the whole User object into your session is a bad idea, and is probably why you're not getting back what you expect. You should implement something like #to_session on your User class that returns a hash with the minimum required information. Something like:
def to_session
{:id => id, :username => username, :email => email}
end
Then when you set the session:
session[:user] = user.to_session