I am using Carrierwave, Fog to store images upload to S3.
The issue is that when I go to edit a record, the "file" & "photo" field automatically goes blank. So if I want to preserve the image or file in the record I have to re-upload it.
Otherwise, what happens is that the uploaded file/image just disappears. I am not even sure if it gets deleted from S3, but the association with my record in the db disappears.
This is my SimpleForm _form.html.erb
partial for my Post
model:
<%= simple_form_for(@post, html: {class: 'form-horizontal' }) do |f| %>
<%= f.error_notification %>
<%= f.input_field :title, placeholder: "Enter Title" %>
<%= f.input_field :body, id: "body-field", placeholder: "Provide all the facts." %>
<%= f.input_field :photo %>
<%= f.input_field :file %>
<%= f.button :submit, class: "btn btn-primary pull-left" %>
<% end %>
Here is my PhotoUploader
class PhotoUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :fog
include CarrierWave::MimeTypes
process :set_content_type
def store_dir
"images/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :main_thumb_mobile do
process :resize_to_fit => [52, 52]
end
version :main_thumb do
process :resize_to_fit => [150, 150]
end
version :post_thumb do
process :resize_to_fit => [200, 200]
end
version :large do
process :resize_to_limit => [400, 400]
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
This is my FileUploader
class FileUploader < CarrierWave::Uploader::Base
storage :fog
def store_dir
"files/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(pdf doc docx xls xlsx ppt pptx txt mp4 m4v mov avi mkv mp3 wav)
end
end
This is the Schema for my Post
:
# == Schema Information
# truncated for brevity
# Table name: posts
#
# id :integer not null, primary key
# title :text
# photo :string(255)
# body :text
# user_id :integer
# file :string(255)
Edit 1
This is my Post.rb
:
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :text
# photo :string(255)
# body :text
# created_at :datetime
# updated_at :datetime
# user_id :integer
# ancestry :string(255)
# file :string(255)
# status :integer default(0)
# slug :string(255)
# publication_status :integer default(0)
# has_eyewitness :boolean default(FALSE)
# youtube_embed_code :text
# soundcloud_embed_code :text
#
class Post < ActiveRecord::Base
has_ancestry
belongs_to :user
resourcify
enum status: [ :unconfirmed, :corroborated, :confirmed ]
enum publication_status: [ :unpublished, :published ]
extend FriendlyId
friendly_id :title, use: [:slugged, :history, :finders]
attr_accessor :country
mount_uploader :photo, PhotoUploader
mount_uploader :file, FileUploader
validates_presence_of :body
validates_length_of :body, maximum: 150, too_long: 'The report must be less than 150 words.',
tokenizer: ->(str) { str.scan(/\w+/) }
validates_length_of :title, maximum: 7, too_long: 'The title must be less than 7 words.',
tokenizer: ->(str) { str.scan(/\w+/) }
def publish
published!
end
def unpublish
unpublished!
end
def is_published?
if self.published?
"yes"
else
"no"
end
end
end
Edit 2
I changed the f.input_field :photo
in my form to f.file_field :photo
per jaspreet's suggestion and it still doesn't work. This is my log from an update request:
Started PATCH "/posts/ognr-takes-over-amcham-6a6f01ba-a9f9-44d5-924a-72f666f20ca8" for 127.0.0.1 at 2014-12-28 13:51:38 -0500
Processing by PostsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"S7FOq956fox6XYpar7Yd6V7AL+bwypQQxZktjHW3PNc=", "post"=>{"parent_id"=>"", "status"=>"unconfirmed", "publication_status"=>"unpublished", "title"=>"OGNR takes over AMCHAM", "body"=>"OGNR storms the rerl.", "has_eyewitness"=>"1", "youtube_embed_code"=>"", "soundcloud_embed_code"=>""}, "commit"=>"Update Post", "id"=>"ognr-takes-over-amcham-6a6f01ba-a9f9-44d5-924a-72f666f20ca8"}
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
(1.2ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
(6.4ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'editor') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
(0.2ms) BEGIN
Post Exists (1.0ms) SELECT 1 AS one FROM "posts" INNER JOIN "friendly_id_slugs" ON "friendly_id_slugs"."sluggable_id" = "posts"."id" AND "friendly_id_slugs"."sluggable_type" = 'Post' WHERE ("posts"."id" IS NOT NULL) AND "posts"."slug" = 'ognr-takes-over-amcham' LIMIT 1
SQL (0.6ms) INSERT INTO "posts" ("body", "created_at", "has_eyewitness", "slug", "soundcloud_embed_code", "title", "updated_at", "youtube_embed_code") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["body", "OGNR storms the rerl."], ["created_at", "2014-12-28 18:51:39.183091"], ["has_eyewitness", "t"], ["slug", "ognr-takes-over-amcham-cd491a8e-9a4e-4d5e-b13a-898de4adf135"], ["soundcloud_embed_code", ""], ["title", "OGNR takes over AMCHAM"], ["updated_at", "2014-12-28 18:51:39.183091"], ["youtube_embed_code", ""]]
FriendlyId::Slug Load (0.5ms) SELECT "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = $1 AND "friendly_id_slugs"."sluggable_type" = $2 ORDER BY "friendly_id_slugs".id DESC LIMIT 1 [["sluggable_id", 43], ["sluggable_type", "Post"]]
SQL (0.4ms) DELETE FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = $1 AND "friendly_id_slugs"."sluggable_type" = $2 AND "friendly_id_slugs"."slug" = 'ognr-takes-over-amcham-cd491a8e-9a4e-4d5e-b13a-898de4adf135' [["sluggable_id", 43], ["sluggable_type", "Post"]]
SQL (0.4ms) INSERT INTO "friendly_id_slugs" ("created_at", "slug", "sluggable_id", "sluggable_type") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", "2014-12-28 18:51:39.242475"], ["slug", "ognr-takes-over-amcham-cd491a8e-9a4e-4d5e-b13a-898de4adf135"], ["sluggable_id", 43], ["sluggable_type", "Post"]]
(2.6ms) COMMIT
Redirected to http://localhost:3000/posts/ognr-takes-over-amcham-cd491a8e-9a4e-4d5e-b13a-898de4adf135
Completed 302 Found in 372ms (ActiveRecord: 17.3ms)
Edit 3
The PostController#Update
looks like this:
class PostsController < ApplicationController
load_and_authorize_resource
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Report was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
Edit 4
You need to use an input field for upload image to show the image name, and use javascript function to display the file name in input field as the following:
<%= text_field_tag 'file_name', "#{@post.photo_file_name}", {disabled: true, class: 'browse-input form-control'} %>
<%= f.input_field :photo %>
:javascript
$("#post_photo").change(function () {
$("#file_name").val(this.value.replace(/^.*[\\\/]/, ''));
});
And You can use the same code for upload file.
For Prevent to re-upload unchanged photo
You can use changed? method to check if photo changed or not as the following:
def update
if @post.photo && [email protected]?
@post.update(post_update_params_without_photo)
end
end
# Example method, don't forgot set the necessary attributes
def post_update_params_without_photo
params.require(:post).permit(:title)
end
Explain: This code to update changed attributes only i.e (title, status, and so on).
I think the simple_form_for is doing some extra work in making params. It might be sending params as 'post' => { 'file' => { 'id' => '29', 'image' => '' } }
, when no file is selected.
Whereas if you try to use a simple file_field_tag
or f.file_field
then it only sends as 'post' => { 'file' => { 'id' => '29' } }
, if no image file is selected, and the old one is preserved.
Try this and it would surely solve your problem.
Remember if using file_field_tag
you need to pass the name
attribute correctly for the params to be built up in the right way as the rails expect. In your case it must be like 'post[file][image]'
and a hidden field too(this is automatically built if using f.file_field
) whose name will be post[file][id]
Sharing my console
Started PATCH "/requirements/2162" for 127.0.0.1 at 2015-01-05 10:44:53 +0530
Processing by RequirementsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mqoPYjGir/3aA/ZFCjpr79KY/xXEoyTd95Dis8HDH7g=", "requirement"=>{"category_ids"=>["40", "47"], "title"=>"gefd gefd gefd", "details"=>"dsfg", "expiration_date(1i)"=>"2015", "expiration_date(2i)"=>"12", "expiration_date(3i)"=>"31", "address_attributes"=>{"street"=>"ewfg", "city"=>"deaf", "country_code"=>"DZ", "state_code"=>"01", "id"=>"60"}}, "commit"=>"Update Requirement", "id"=>"2162"}
User Load (4.3ms) SELECT `people`.* FROM `people` WHERE `people`.`type` IN ('User') AND `people`.`id` = 28 ORDER BY `people`.`id` ASC LIMIT 1
Requirement Load (1.0ms) SELECT `requirements`.* FROM `requirements` WHERE `requirements`.`id` = 2162 LIMIT 1
(1.7ms) BEGIN
Category Load (6.1ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (40, 47)
Category Load (5.0ms) SELECT `categories`.* FROM `categories` INNER JOIN `category_requirements` ON `categories`.`id` = `category_requirements`.`category_id` WHERE `category_requirements`.`requirement_id` = 2162
Address Load (0.4ms) SELECT `addresses`.* FROM `addresses` WHERE `addresses`.`id` = 60 LIMIT 1
DonorRequirement Exists (0.4ms) SELECT 1 AS one FROM `donor_requirements` WHERE `donor_requirements`.`requirement_id` = 2162 LIMIT 1
SQL (7.6ms) UPDATE `requirements` SET `expiration_date` = '2015-12-31', `title` = 'gefd gefd gefd', `updated_at` = '2015-01-05 05:14:53' WHERE `requirements`.`id` = 2162
(6.0ms) COMMIT
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With