Unable to pass uploaded file to model - ruby-on-rails

I am relatively new to rails cannot get the following code to work. I am trying to upload a data file (Excel or csv), copy it to a temp folder and create a record in a Datafiles model which holds basic file information, such as filename, type, and date. Then I want to read the file and use the data to create or update records in several other models. If all goes well, move the file to a permanent location and write the new path in the Datafiles record.
Controller:
def new
#datafile = Datafile.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #datafile }
end
end
def create
#datafile = Datafile.new(params[:upload])
#datafile.save!
redirect_to datafile_path(#datafile), :notice => "Successfully imported datafile"
rescue => e
logger.error( 'Upload failed. ' + e.to_s )
flash[:error] = 'Upload failed. Please try again.'
render :action => 'new'
end
View:
<%= form_for #datafile, :html => {:multipart => true} do |f| %>
<p>
<%= f.label(:upload, "Select File:") %>
<%= f.file_field :upload %>
</p>
<p> <%= f.submit "Import" %> </p>
<% end %>
Model:
require 'spreadsheet'
class Datafile < ActiveRecord::Base
attr_accessor :upload
attr_accessible :upload
before_create :upload_file
def upload_file
begin
File.open(Rails.root.join('uploads/temp', upload.original_filename), 'wb') do |file|
file.write(upload.read)
self.filename = upload.original_filename
Spreadsheet.client_encoding = 'UTF-8'
#book = Spreadsheet.open(file.path)
self.import
end
rescue => e
#upload_path = Rails.root.join('uploads/temp', upload.original_filename)
File.delete(#upload_path) if File::exists?(#upload_path)
raise e
end
end
def import
case #book.worksheet(0).row(0)[0]
when "WIP Report - Inception to Date"
self.report_type = 'WIP'
puts 'report_type assigned'
self.import_wip
else
self.report_type = 'Unknown'
end
end
def import_wip
self.end_date = #book.worksheet(0).row(0)[3]
puts 'end_date assigned'
end
def formatted_end_date
end_date.strftime("%d %b, %Y")
end
end
However, it fails and the rails server window says
Started POST "/datafiles" for 127.0.0.1 at 2011-05-24 16:05:25 +0200
Processing by DatafilesController#create as HTML
Parameters: {"utf8"=>"✓", "datafile"=>{"upload"=>#<ActionDispatch::Http::UploadedFile:0xa0282d0 #original_filename="wip.xls", #content_type="application/vnd.ms-excel", #headers="Content-Disposition: form-data; name=\"datafile[upload]\"; filename=\"wip.xls\"\r\nContent-Type: application/vnd.ms-excel\r\n", #tempfile=#<File:/tmp/RackMultipart20110524-14236-1kcu3hm>>}, "commit"=>"Import"}
Upload failed. undefined method `original_filename' for nil:NilClass
Rendered datafiles/new.html.erb within layouts/application (54.5ms)
Completed 200 OK in 131ms (Views: 56.3ms | ActiveRecord: 0.0ms)
I have rspec model tests that pass and controller tests that fail to redirect after saving. I can post them if it would be useful.
I inserted the raise #datafile.to_yaml and got the following in the terminal.
ERROR RuntimeError: --- !ruby/object:Datafile
attributes:
filename:
report_type:
import_successful:
project:
begin_date:
end_date:
created_at:
updated_at:
attributes_cache: {}
changed_attributes: {}
destroyed: false
marked_for_destruction: false
persisted: false
previously_changed: {}
readonly: false
I notice that :upload is not listed. Can I set model instance variables from the form? :upload is an instance variable, not an attribute, because I do not want to keep the uploaded file in the database (just its path to the local directory). If I cannot set instance variables in the view's form, any suggestions? Does it make sense (in terms of MVC) to upload the file to a temp folder in the controller, then create a model record by passing it the temp file's path?

Hello I am pretty new to Rails and was strugling with this as well I found a solution though it probably isn't the best. It does work though.
in you model make a public function called import_upload
def import_upload( upload )
#uploaded_file = upload
end
now in your controller you can explicitly pass it. I don't know why this doesn't happen automatically if you make an attr_accsessor with the same name as the file_field but this was the solution that worked for me.
def new
foo = Foo.new( params[:foo] )
foo.import_upload( params[:foo][:uploaded_file] ) #This is were the majic happens
#Do your saving stuff and call it a day
end

Related

form submit in rails not working, possible routing/path error unsure why?

I am trying to submit a form in rails that is just a pdf uplaod (using paperclip). There is something wrong with either my form, controller or model and i am not sure which.
this is my form:
<%= form_for #yearguide, :html => { :multipart => true } do |form| %>
<%= form.file_field :pdf %>
<%= form.submit "Add Event", class: "btn btn-primary" %>
<% end %>
my controller:
class YearController < ApplicationController
def new
#yearguide = Year.create(year_params)
end
def create
if #yearguide = Year.save
redirect_to '/'
else
render 'new'
end
end
my model:
class YearlyGuide < ActiveRecord::Base
has_attached_file :pdf
validates_attachment :document, content_type: { content_type: "application/pdf" }
end
my routes:
resources :year
I add the file and press upload, but I am being redirected to 'update.html.erb'.
The file doesn;t exist in the db, just an empty record.
When i debug the params on pressing uplaod I get this output
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"G7ZrXEiip/gsqhDObcfYhTT9kerYZGk+Zl29kWA5jos=", "year"=>{"pdf"=>#<ActionDispatch::Http::UploadedFile:0x000001029b0340 #tempfile=#<Tempfile:/var/folders/ns/ry6z7jfd6qg6j8xr2q6dw0yc0000gn/T/RackMultipart20140609-21455-1eg1sk3>, #original_filename="Artsmill Hebden Bridge Exhibition Programme 2014.pdf", #content_type="application/pdf", #headers="Content-Disposition: form-data; name=\"year[pdf]\"; filename=\"Artsmill Hebden Bridge Exhibition Programme 2014.pdf\"\r\nContent-Type: application/pdf\r\n">}, "commit"=>"Add Event", "action"=>"update", "controller"=>"year", "id"=>"9"}
=========================
EDIT
OK, so discrepancies with my naming led to the previosu errors, i started again, generating:
rails g model YearlyGuide pdf:attachment start:datetime end:datetime
rails g controller YearlyGuide new index show
now in my routes i have added
resources :yearly_guides
when i visit
/yearly_guides/new
I get this error
uninitialized constant YearlyGuidesController
I am really at a loss as to what I am doing wrong, I have done this before and never had these issues.
#iceman, thanks for your help and patience thus far.
The controller is not doing what it's supposed to do. This is the bare bones basic scheme of creating a new object in Rails.
class YearsController < ApplicationController
def new
#yearguide = Year.new
end
def create
#yearguide = Year.create(year_params)
if #yearguide.save
redirect_to '/' # I would consider redirect_to #yearguide to show the newly created object
else
render 'new'
end
end
end
EDIT:
You have to update your routes.rb to
resources :years
Since you are creating the yearguide object, rails infer that you have to do put/patch request, so request is going to update since rails getting id.
You have two options.
1) Change new method of controller like below
class YearController < ApplicationController
def new
#yearguide = Year.new
end
end
2) Override the method parameter by passing method params as 'post' inside your form tag

Problems simply uploading a file

I created a form where the user can upload a file: :File is a column in my Setting model
<%= form_for(#setting) do |f| %>
<div class="field">
<%= f.label 'Patientendaten' %>
<%= f.file_field :file %>
</div>
.......
There is no problem when I don't upload a file and just edit other "settings". But when I try to upload a file I get this error:
NoMethodError in SettingsController#update
undefined method `name' for nil:NilClass
app/controllers/settings_controller.rb:72:in `block in update'
app/controllers/settings_controller.rb:71:in `update'
The corresponding params are:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"eFchgMpE0A46jQI0asmiR2wH+4kq/vmSzDchlBmMJaA=",
"setting"=>{"adobe"=>"",
"file"=>#<ActionDispatch::Http::UploadedFile:0x3764b98 #original_filename="prawn.rb",
#content_type="application/octet-stream",
#headers="Content-Disposition: form-data; name=\"setting[file]\"; filename=\"prawn.rb\"\r\nContent-Type: application/octet-stream\r\n",
#tempfile=#<File:C:/Users/STADLE~1/AppData/Local/Temp/RackMultipart20130919-6776- 1bs1n2d>>,
"treiber"=>"",
"port"=>"",
"druckername"=>"",
"bild"=>"C:/geburtstag/app/vorderseite/default.jpg",
"anrede"=>"",
"text"=>""},
"commit"=>"Speichern",
"id"=>"1"}
I suppose that the error occurs because of the params?
If you want to see my controller:
def update
#setting = Setting.find(params[:id])
respond_to do |format|
if #setting.update_attributes(params[:setting])
pdf = Prawn::Document.new(:page_size=> "A4",:margin => 0)
pdf.image #setting.bild ,:at => [0, Prawn::Document::PageGeometry::SIZES["A4"][1]],:fit => Prawn::Document::PageGeometry::SIZES["A4"]
Dir.chdir Rails.root.to_s + '/vorderseite' do |dir|
pdf.render_file "vorderseite.pdf"
end
format.html { redirect_to patients_path, notice: 'Setting was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #setting.errors, status: :unprocessable_entity }
end
end
end
Model:
class Setting < ActiveRecord::Base
attr_accessible :anrede, :text, :adobe , :bild, :treiber, :port, :druckername, :file
before_save :default_values
def default_values
self.bild = Rails.root.to_s + '/vorderseite/default.jpg' if self.bild.blank?
end
end
The problem is how you manage upload : you can't just pass what an input[type="file"] produces to the database, especially a fields of type String : when you upload a file, it's only provided as temporary file, you have to persist it somewhere, and make database remember its path.
You can see what rails guides has to say about how to handle uploads. With the recommanded method, you would remove the "file" attribute from your model (and attr_accessible), take the IO generated by upload in params in your controller, write its content somewhere in the filesystem and then save the filepath (probably in the bild attribute).
But that may be time consuming and it's prone to security problems (you have to take special care to prevent someone uploading a file named ../../../../../../../../etc/passwords which would override your server password files, for example).
In real case scenario, we often use third party libs to handle uploads, like Paperclip or Carrierwave.
With Paperclip, for example, you would add something like that in your model :
class Setting < ActiveRecord::Base
attr_accessible :anrede, :text, :adobe , :bild, :treiber, :port, :druckername
has_attached_file :bild
end
(provided your upload field is bild).
This will let you do exactly what you currently do :
#setting.update_attribute( params[ :setting ] )
See paperclip documentation for more details.
Edit : added more info on temporary file in first paragraph
You should use multipart form to upload files:-
form_for #user, :html => { :multipart => true } do |f...

Paperclip gem with Rails 4 doesn't save non-file fields

I'm building a Rails 4 app with the paperclip gem in which users can upload a video file from a form with several other fields (uploader_first_name, uploader_last_name, uploader_email).
The paperclip installation went smoothly (although I needed to add gem 'protected_attributes'
) and I'm able to save file to the correct and create the corresponding records in the videos table, however all the non-paperclip fields are null and I'm not sure why.
class Video < ActiveRecord::Base
belongs_to :project
attr_accessible :file
has_attached_file :file, :url=>"/tmp/video_uploads", :path=>":rails_root/tmp/video_uploads"
end
class VideosController < ApplicationController
def save
#video = Video.create(params[:video])
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
#I tried with this too...
#private
#def video_params
#params.require(:video).permit( :uploader_first_name, :uploader_last_name, :uploader_email)
#end
end
In the view...
<h2>Upload your video</h2>
<% myclass = {:class=>'form-control'} %>
<%= form_for(:video, :url => {:action=>'save', :controller=>'videos'}, :html=>{:class=>'upload-form-js', :multipart=> true} ) do |f| %>
<div class="form-group">
<%= f.label(:uploader_first_name, "First Name") %>
<%= f.text_field(:uploader_first_name, myclass) %>
</div>
<div class="form-group">
<%= f.label(:uploader_last_name, "Last Name") %>
<%= f.text_field(:uploader_last_name, myclass) %>
</div>
<div class="form-group">
<%= f.label(:uploader_email, "Email") %>
<%= f.text_field(:uploader_email, myclass) %>
</div>
<div class="form-group">
<label>Video File</label>
<input type="file" name="video[file]" id="video_file"/></span>
</div>
<%= f.submit('Upload', {class: 'btn btn-primary btn-block'}) %>
<% end %>
Update 1
I changed to this...
class VideosController < ApplicationController
def save
#video = Video.create( video_params )
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
private
def video_params
params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email)
end
end
...and now I get this error:
Errno::EISDIR in VideosController#save
Is a directory - /Applications/MAMP/htdocs/clippo2/tmp/video_uploads
Don't I want the url/path to point to a directory?
Update 2
I changed the video model to...
has_attached_file :file, :url=>"/tmp/video_uploads/:basename.:extension", :path=>":rails_root/tmp/video_uploads/:basename.:extension"
...and now no errors, files get saved to the right directory and the corresponding fields added to the new row, but all other fields are still NULL (original problem).
Update 3
I turned on the debugger and here's what I see after I try to upload a file. It looks like a strong parameters error but I'm not sure how to fix it:
Started POST "/videos/save" for 127.0.0.1 at 2013-08-27 09:21:34 -0400
Processing by VideosController#save as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"es4wPqFr9xPBUFsbHQR/gAzofDC+ZwYsiiJ7RAQZUHk=", "video"=>{"uploader_first_name"=>"adsfasdf", "uploader_last_name"=>"asdfasdf", "uploader_email"=>"asdfasdf", "file"=>#<ActionDispatch::Http::UploadedFile:0x007fc4782e31e8 #tempfile=#<Tempfile:/var/folders/f2/jhv7xx0j3hlckhcg_jbv6hr00000gn/T/RackMultipart20130827-89636-188f0hs>, #original_filename="sample_iPod.m4v", #content_type="video/mp4", #headers="Content-Disposition: form-data; name=\"video[file]\"; filename=\"sample_iPod.m4v\"\r\nContent-Type: video/mp4\r\n">, "project_hashed_id"=>"1377539908"}, "commit"=>"Upload"}
{"utf8"=>"✓", "authenticity_token"=>"es4wPqFr9xPBUFsbHQR/gAzofDC+ZwYsiiJ7RAQZUHk=", "video"=>{"uploader_first_name"=>"adsfasdf", "uploader_last_name"=>"asdfasdf", "uploader_email"=>"asdfasdf", "file"=>#<ActionDispatch::Http::UploadedFile:0x007fc4782e31e8 #tempfile=#<Tempfile:/var/folders/f2/jhv7xx0j3hlckhcg_jbv6hr00000gn/T/RackMultipart20130827-89636-188f0hs>, #original_filename="sample_iPod.m4v", #content_type="video/mp4", #headers="Content-Disposition: form-data; name=\"video[file]\"; filename=\"sample_iPod.m4v\"\r\nContent-Type: video/mp4\r\n">, "project_hashed_id"=>"1377539908"}, "commit"=>"Upload", "controller"=>"videos", "action"=>"save"}
Unpermitted parameters: project_hashed_id
WARNING: Can't mass-assign protected attributes for Video: uploader_first_name, uploader_last_name, uploader_email
app/controllers/videos_controller.rb:6:in `save'
[1m[35m (0.2ms)[0m BEGIN
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO `videos` (`created_at`, `file_content_type`, `file_file_name`, `file_file_size`, `file_updated_at`, `updated_at`) VALUES ('2013-08-27 13:21:34', 'video/mp4', 'sample_iPod.m4v', 2236480, '2013-08-27 13:21:34', '2013-08-27 13:21:34')[0m
[1m[35m (9.0ms)[0m COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 21ms (ActiveRecord: 9.5ms)
Welcome to the rails 4. 'attr_accessible' was replaced by the strong parameters.
http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
Upd. Can you try this?
def create
#video = Video.create(video_params)
end
private
def video_params
params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email)
end
I figured out what's going on. The strong parameters were getting in the way because I'm using attr_accessible in the model. Instead of fiddling with the require() and permit() I removed them entirely and added the missing fields to the attr_accessible and now it works:
class Video < ActiveRecord::Base
belongs_to :project
attr_accessible :file, :uploader_first_name, :uploader_last_name, :project_hashed_id, :uploader_email, :rating
has_attached_file :file, :url=>"/tmp/video_uploads/:basename.:extension", :path=>":rails_root/tmp/video_uploads/:basename.:extension"
end
class VideosController < ApplicationController
def save
logger.debug( params )
##video = Video.new( video_params )
#video = Video.new( params[:video])
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
end
I realize that attr_accessible was replaced by strong parameters in Rails 4 but I couldn't get paperclip to work without it. If anyone can tell me how, I'd love to know.
Update
I removed attr_accessible entirely and just used the strong parameters...
class VideosController < ApplicationController
def save
logger.debug( params )
#video = Video.new( video_params )
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
private
def video_params
#params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email, :project_hashed_id)
params.require(:video).permit!
end
end
...and it works BUT you have to remember to remove the protected_attributes gem and restart rails s for it to take effect (this n00b mistake cost me 45 minutes!)
Moral of this story: Don't mix and match attr_accessible with strong params. Do one or the other and paperclip will work with strong parameters.

Not losing paperclip attachment when model cannot be saved due to validation error

The scenario is a normal model that contains a paperclip attachment along with some other columns that have various validations. When a form to to create an object cannot be saved due to a validation error unrelated to the attachment, columns like strings are preserved and remain prefilled for the user, but a file selected for uploading is completely lost and must be reselected by the user.
Is there a standard approach to preserving the attachment in the case of a model validation error? This seems like a very common use case.
It seems inelegant to hack up a solution where the file is saved without an owner and then reconnected to the object after it's successfully saved so I'm hoping to avoid this.
Switch to using CarrierWave. I know this was in a comment, but I just spent all day making the transition so my answer may be helpful still.
First you can follow a great railscast about setting up carrier wave: http://railscasts.com/episodes/253-carrierwave-file-uploads
To get it to preserve the image between posts, you need to add a hidden field with the suffix 'cache':
<%= form_for #user, :html => {:multipart => true} do |f| %>
<p>
<label>My Avatar</label>
<%= f.file_field :avatar %>
<%= f.hidden_field :avatar_cache %>
</p>
<% end %>
For Heroku
And if you're deploying to Heroku like I am, you need to make some changes to get it to work, since the caching works by temporarily saving uploads in a directory called public/uploads. Since the filesystem is readonly in Heroku, you need to have it use the tmp folder instead, and have rack serve static files from there.
Tell carrierwave to use the tmp folder for caching.
In your config/initializers/carrierwave.rb (feel free to create if not there), add:
CarrierWave.configure do |config|
config.root = Rails.root.join('tmp')
config.cache_dir = 'carrierwave'
end
Configure rack to serve static files in from the tmp/carrierwave folder
In your config.ru file, add:
use Rack::Static, :urls => ['/carrierwave'], :root => 'tmp'
For an example of a fully functional barebones rails/carrierwave/s3/heroku app, check out:
https://github.com/trevorturk/carrierwave-heroku (no affiliation, just was useful).
Hope this helps!
I had to fix this on a recent project using PaperClip. I've tried calling cache_images() using after_validation and before_save in the model but it fails on create for some reason that I can't determine so I just call it from the controller instead.
model:
class Shop < ActiveRecord::Base
attr_accessor :logo_cache
has_attached_file :logo
def cache_images
if logo.staged?
if invalid?
FileUtils.cp(logo.queued_for_write[:original].path, logo.path(:original))
#logo_cache = encrypt(logo.path(:original))
end
else
if #logo_cache.present?
File.open(decrypt(#logo_cache)) {|f| assign_attributes(logo: f)}
end
end
end
private
def decrypt(data)
return '' unless data.present?
cipher = build_cipher(:decrypt, 'mypassword')
cipher.update(Base64.urlsafe_decode64(data).unpack('m')[0]) + cipher.final
end
def encrypt(data)
return '' unless data.present?
cipher = build_cipher(:encrypt, 'mypassword')
Base64.urlsafe_encode64([cipher.update(data) + cipher.final].pack('m'))
end
def build_cipher(type, password)
cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').send(type)
cipher.pkcs5_keyivgen(password)
cipher
end
end
controller:
def create
#shop = Shop.new(shop_params)
#shop.user = current_user
#shop.cache_images
if #shop.save
redirect_to account_path, notice: 'Shop created!'
else
render :new
end
end
def update
#shop = current_user.shop
#shop.assign_attributes(shop_params)
#shop.cache_images
if #shop.save
redirect_to account_path, notice: 'Shop updated.'
else
render :edit
end
end
view:
= f.file_field :logo
= f.hidden_field :logo_cache
- if #shop.logo.file?
%img{src: #shop.logo.url, alt: ''}
Following the idea of #galatians , i got this solution (and worked beautfully )
Created a repo to that example:
* https://github.com/mariohmol/paperclip-keeponvalidation
The first thing to do is put some methods in your base active record, so every model that uses attach you can make it work
In config/initializers/active_record.rb
module ActiveRecord
class Base
def decrypt(data)
return '' unless data.present?
cipher = build_cipher(:decrypt, 'mypassword')
cipher.update(Base64.urlsafe_decode64(data).unpack('m')[0]) + cipher.final
end
def encrypt(data)
return '' unless data.present?
cipher = build_cipher(:encrypt, 'mypassword')
Base64.urlsafe_encode64([cipher.update(data) + cipher.final].pack('m'))
end
def build_cipher(type, password)
cipher = OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC').send(type)
cipher.pkcs5_keyivgen(password)
cipher
end
#ex: #avatar_cache = cache_files(avatar,#avatar_cache)
def cache_files(avatar,avatar_cache)
if avatar.queued_for_write[:original]
FileUtils.cp(avatar.queued_for_write[:original].path, avatar.path(:original))
avatar_cache = encrypt(avatar.path(:original))
elsif avatar_cache.present?
File.open(decrypt(avatar_cache)) {|f| assign_attributes(avatar: f)}
end
return avatar_cache
end
end
end
After that , include in your model and attached field, the code above
In exemple, i included that into /models/users.rb
has_attached_file :avatar, PaperclipUtils.config
attr_accessor :avatar_cache
def cache_images
#avatar_cache=cache_files(avatar,#avatar_cache)
end
In your controller, add this to get from cache the image (just before the point where you save the model)
#user.avatar_cache = params[:user][:avatar_cache]
#user.cache_images
#user.save
And finally include this in your view, to record the location of the current temp image
f.hidden_field :avatar_cache
If you want to show in view the actual file, include it:
<% if #user.avatar.exists? %>
<label class="field">Actual Image </label>
<div class="field file-field">
<%= image_tag #user.avatar.url %>
</div>
<% end %>
As of Sept 2013, paperclip has no intention of "fixing" the losing of attached files after validation. "The problem is (IMHO) more easily and more correctly avoided than solved"
https://github.com/thoughtbot/paperclip/issues/72#issuecomment-24072728
I'm considering the CarrierWave solution proposed in John Gibb's earlier solution
Also check out refile (newer option)
Features:
Configurable backends, file system, S3, etc...
Convenient integration with ORMs
On the fly manipulation of images and other files
Streaming IO for fast and memory friendly uploads
Works across form redisplays, i.e. when validations fail, even on S3
Effortless direct uploads, even to S3
Support for multiple file uploads
https://gorails.com/episodes/file-uploads-with-refile
If the image isn't required why not split the form into two stages, the first one creates the object, the second page lets you add optional information (like a photo).
Alternatively you could validate the form as the user enters the information so that you don't have to submit the form to find out your data is invalid.
save your picture first than try the rest
lets say you have a user with a paperclip avatar:
def update
#user = current_user
unless params[:user][:avatar].nil?
#user.update_attributes(avatar: params[:user][:avatar])
params[:user].delete :avatar
end
if #user.update_attributes(params[:user])
redirect_to edit_profile_path, notice: 'User was successfully updated.'
else
render action: "edit"
end
end
In view file just put if condition that should accept only the record which had valid id.
In my scenario this is the code snippet
<p>Uploaded files:</p>
<ul>
<% #user.org.crew.w9_files.each do |file| %>
<% if file.id.present? %>
<li> <%= rails code to display value %> </li>
<% end %>
<% end %>
</ul>

How to parse the contents of a uploaded file in RoR

I am new to Rails.
In my project where users have to upload a file, I store it
then I have to parse the file contents and show it in new form.
I have successfully done the file uploading portion,
now how should I read the contents of it?
Try something like this:
upload = params[:your_upload_form_element]
content = upload.is_a?(StringIO) ? upload.read : File.read(upload.local_path)
Very small files can be passed as strings instead of uploaded files, therefore you should check for that and handle it accordingly.
You can open files and read their contents in Ruby using the File class, as this simple example demonstrates:
# Open a file in read-only mode and print each line to the console
file = File.open('afile.txt', 'r') do |f|
f.each do |line|
puts line
end
end
Complete Example
Take, for example, uploading an import file containing contacts. You don't need to store this import file, just process it and discard it.
Routes
routes.rb
resources :contacts do
collection do
get 'import/new', to: :new_import # import_new_contacts_path
post :import, on: :collection # import_contacts_path
end
end
Form
views/contacts/new_import.html.erb
<%= form_for #contacts, url: import_contacts_path, html: { multipart: true } do |f| %>
<%= f.file_field :import_file %>
<% end %>
Controller
controllers/contacts_controller.rb
def new_import
end
def import
begin
Contact.import( params[:contacts][:import_file] )
flash[:success] = "<strong>Contacts Imported!</strong>"
redirect_to contacts_path
rescue => exception
flash[:error] = "There was a problem importing that contacts file.<br>
<strong>#{exception.message}</strong><br>"
redirect_to import_new_contacts_path
end
end
Contact Model
models/contact.rb
def import import_file
File.foreach( import_file.path ).with_index do |line, index|
# Process each line.
# For any errors just raise an error with a message like this:
# raise "There is a duplicate in row #{index + 1}."
# And your controller will redirect the user and show a flash message.
end
end
Hope that helps others!
JP

Resources