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...
Related
So as it stands I have a form partial which starts off as:
<%= form_for(#merchandise) do |f| %>
It works perfectly for editing the data that I have already assigned in the rails console. When I try to use it for a "new" form that creates new merchandise (in this case the singular form of merchandise, I don't have nested resources, multiple models etc.), I get a no Method error that states
"undefined method 'merchandises_path' for #<#<Class:0x64eaef0>:0x95d2370>".
When I explicitly state the URL in the form_for method:
<%= form_for(#merchandise url:new_merchandise_path) do |f| %>
I get it to open and I finally have access to the form, however in this case I get a routing error that states
"No route matches [POST] "merchandise/new"".
I decided to write out that route in my routes file which previously just had:
root "merchandise#index" resources :merchandise
After I add the route it literally does nothing. I click submit and it takes me to the form but there is no new data in the database. I am at a complete loss and have been at this for hours googling and stack overflowing and I just don't know what to do anymore. All help is seriously appreciated. I'm adding a pastebin with all my code in the following url:
http://pastebin.com/HDJdTMDt
I have two options for you to fix it:
Option 1:
Please try to do this for best practice in Rails:
routes.rb
change your routes use plural
resources :merchandises
merchandises_controller.rb
Rename your file controller and class into MerchandisesController
class MerchandisesController < ApplicationController
def index
#merchandise = Merchandise.all
end
def new
#merchandise = Merchandise.new
end
def create
#merchandise = Merchandise.new(merchandise_params)
if #merchandise.save
redirect_to merchandises_path
else
render :new
end
end
def show
#merchandise = Merchandise.find(params[:id])
end
def edit
#merchandise = Merchandise.find(params[:id])
end
def update
#merchandise = Merchandise.find(params[:id])
if #merchandise.update(merchandise_params)
redirect_to #merchandise, notice: "The movie was updated"
else
render :edit
end
end
def merchandise_params
params.require(:merchandise).permit(:shipper, :cosignee, :country_arrival_date, :warehouse_arrival_date, :carrier, :tracking_number, :pieces, :palets, :width, :height, :length, :weight, :description, :cargo_location, :tally_number, :customs_ref_number, :released_date, :updated_by, :country_shipped_to, :country_shipped_from)
end
end
Option 2:
If you want to not change many code
/merchandise/_form.html.erb
in partial file
/merchandise/new.html.erb
<%= render 'form', url: merchandise_path, method: 'post' %>
/merchandise/edit.html.erb
<%= render 'form', url: category_path(#merchendise.id), method: 'put' %>
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
I'm writing some image upload code for Ruby on Rails with Paperclip, and I've got a working solution but it's very hacky so I'd really appreciate advice on how to better implement it. I have an 'Asset' class containing information about the uploaded images including the Paperclip attachment, and a 'Generator' class that encapsulates sizing information. Each 'Project' has multiple assets and generators; all Assets should be resized according to the sizes specified by each generator; each Project therefore has a certain set of sizes that all of its assets should have.
Generator model:
class Generator < ActiveRecord::Base
attr_accessible :height, :width
belongs_to :project
def sym
"#{self.width}x#{self.height}".to_sym
end
end
Asset model:
class Asset < ActiveRecord::Base
attr_accessible :filename,
:image # etc.
attr_accessor :generators
has_attached_file :image,
:styles => lambda { |a| a.instance.styles }
belongs_to :project
# this is utterly horrendous
def styles
s = {}
if #generators == nil
#generators = self.project.generators
end
#generators.each do |g|
s[g.sym] = "#{g.width}x#{g.height}"
end
s
end
end
Asset controller create method:
def create
#project = Project.find(params[:project_id])
#asset = Asset.new
#asset.generators = #project.generators
#asset.update_attributes(params[:asset])
#asset.project = #project
#asset.uploaded_by = current_user
respond_to do |format|
if #asset.save_(current_user)
#project.last_asset = #asset
#project.save
format.html { redirect_to project_asset_url(#asset.project, #asset), notice: 'Asset was successfully created.' }
format.json { render json: #asset, status: :created, location: #asset }
else
format.html { render action: "new" }
format.json { render json: #asset.errors, status: :unprocessable_entity }
end
end
end
The problem I am having is a chicken-egg issue: the newly created Asset doesn't know which generators (size specifications) to use until after it's been instantiated properly. I tried using #project.assets.build, but then the Paperclip code is still executed before the Asset gets its project association set and nils out on me.
The 'if #generators == nil' hack is so the update method will work without further hacking in the controller.
All in all it feels pretty bad. Can anyone suggest how to write this in a more sensible way, or even an approach to take for this kind of thing?
Thanks in advance! :)
I ran into the same Paperclip chicken/egg issue on a project trying to use dynamic styles based on the associated model with a polymorphic relationship. I've adapted my solution to your existing code. An explanation follows:
class Asset < ActiveRecord::Base
attr_accessible :image, :deferred_image
attr_writer :deferred_image
has_attached_file :image,
:styles => lambda { |a| a.instance.styles }
belongs_to :project
after_save :assign_deferred_image
def styles
project.generators.each_with_object({}) { |g, hsh| hsh[g.sym] = "#{g.width}x#{g.height}" }
end
private
def assign_deferred_image
if #deferred_image
self.image = #deferred_image
#deferred_image = nil
save!
end
end
end
Basically, to get around the issue of Paperclip trying to retrieve the dynamic styles before the project relation information has been propagated, you can assign all of the image attributes to a non-Paperclip attribute (in this instance, I have name it deferred_image). The after_save hook assigns the value of #deferred_image to self.image, which kicks off all the Paperclip jazz.
Your controller becomes:
# AssetsController
def create
#project = Project.find(params[:project_id])
#asset = #project.assets.build(params[:asset])
#asset.uploaded_by = current_user
respond_to do |format|
# all this is unrelated and can stay the same
end
end
And the view:
<%= form_for #asset do |f| %>
<%# other asset attributes %>
<%= f.label :deferred_upload %>
<%= f.file_field :deferred_upload %>
<%= f.submit %>
<% end %>
This solution also allows using accepts_nested_attributes for the assets relation in the Project model (which is currently how I'm using it - to upload assets as part of creating/editing a Project).
There are some downsides to this approach (ex. validating the Paperclip image in relation to the validity of the Asset instance gets tricky), but it's the best I could come up with short of monkey patching Paperclip to somehow defer execution of the style method until after the association information had been populated.
I'll be keeping an eye on this question to see if anyone has a better solution to this problem!
At the very least, if you choose to keep using your same solution, you can make the following stylistic improvement to your Asset#styles method:
def styles
(#generators || project.generators).each_with_object({}) { |g, hsh| hsh[g.sym] = "#{g.width}x#{g.height}" }
end
Does the exact same thing as your existing method, but more succinctly.
While I really like Cade's solution, just a suggestion. It seems like the 'styles' belong to a project...so why aren't you calculating the generators there?
For example:
class Asset < ActiveRecord::Base
attr_accessible :filename,
:image # etc.
attr_accessor :generators
has_attached_file :image,
:styles => lambda { |a| a.instance.project.styles }
end
class Project < ActiveRecord::Base
....
def styles
#generators ||= self.generators.inject {} do |hash, g|
hash[g.sym] = "#{g.width}x#{g.height}"
end
end
end
EDIT: Try changing your controller to (assuming the project has many assets):
def create
#project = Project.find(params[:project_id])
#asset = #project.assets.new
#asset.generators = #project.generators
#asset.update_attributes(params[:asset])
#asset.uploaded_by = current_user
end
I've just solved a similar problem that I had.
In my "styles" lambda I am returning a different style depending on the value of a "category" attribute. The problem though is that Image.new(attrs), and image.update_attributes(attrs) doesn't set the attributes in a predictable order, and thus I can't be guaranteed that image.category will have a value before my styles lambda is called. My solution was to override attributes=() in my Image model as follows:
class Image
...
has_attached_file :image, :styles => my_lambda, ...
...
def attributes=(new_attributes, guard_protected_attributes = true)
return unless new_attributes.is_a?(Hash)
if new_attributes.key?("image")
only_attached_file = {
"image" => new_attributes["image"]
}
without_attached_file = new_attributes
without_attached_file.delete("image")
# set the non-paperclip attributes first
super(without_attached_file, guard_protected_attributes)
# set the paperclip attribute(s) after
super(only_attached_file, guard_protected_attributes)
else
super(new_attributes, guard_protected_attributes)
end
end
...
end
This ensures that the paperclip attribute is set after the other attributes and can thus use them in a :style lambda.
It clearly won't help in situations where the paperclip attribute is "manually" set. However in those circumstances you can help yourself by specifying a sensible order. In my case I could write:
image = Image.new
image.category = "some category"
image.image = File.open("/somefile") # styles lambda can use the "category" attribute
image.save!
(Paperclip 2.7.4, rails 3, ruby 1.8.7)
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
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>