bonesjones
bonesjones

Reputation: 144

SimpleForm + Carrierwave - Image upload not saving properly

I am building a Rails app where I need users to upload a profile image on the registration form/have an image edit feature for profile photo. Carrierwave should be properly installed and so far Devise seems to be running fine. When I go to upload the photo and then click "Create Profile", it simply refreshes to the same page and resets the file upload field each time.

SOLUTION: Updated update method in controller to:

 def update
   @pet = Pet.find(params[:id])

 if @pet.update(pet_params)
    redirect_to pets_path
 else
     render :edit
   end
 end

It's uploaded in my app/uploaders/profile_photo_uploader.rb file:

 class ProfilePhotoUploader < CarrierWave::Uploader::Base
    storage :file
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
 end

I have a "profile_photo" string in my schema, as well.

And my controller actions for create and edit/update are here:

 def create
   @pet = Pet.new(pet_params)

   if @pet.save
     flash[:notice] = 'Your pet profile was saved!'
     redirect_to pets_path
   else
     flash.now[:notice] = 'Your pet profile could not be saved.'
     render :new
   end
 end

 def show
   @pet = Pet.find(params[:id])
 end

 def edit
   @pet = Pet.find(params[:id])
 end

 def update
   @pet = Pet.find(params[:id])

   if @pet.save
     redirect_to pets_path
   else
     render :edit
   end
 end

 def pet_params
   params.require(:pet).permit(:name, :breed, :age,
     :color, :weight, :personality, :favorite_things, :owner_id, :profile_photo)
 end

My new form using SimpleForm:

<h1>New Pet Profile</h1>

<%= simple_form_for @pet, html: { multipart: true } do |f| %>
  <%= f.input :name, required: true, label: "Pet Name:"  %>
  <%= f.input :profile_photo, type: :file %>
                   ...
  <%= f.button :submit %>
<% end %>

Routes:

 Rails.application.routes.draw do
   devise_for :owners

   resources :pets

   resources :owners do
     resources :pets, shallow: true
   end
 end

Application Controller:

 class ApplicationController < ActionController::Base
   protect_from_forgery with: :exception

   before_action :configure_permitted_parameters, if: :devise_controller?

   protected

   def configure_permitted_parameters
     devise_parameter_sanitizer.for(:sign_up) << :profile_photo
   end
 end

Upvotes: 0

Views: 3037

Answers (1)

6ft Dan
6ft Dan

Reputation: 2445

You need to have your model set app/models/pet.rb with

class Pet < ActiveRecord::Base
  validates_presence_of :profile_photo
  belongs_to :owner
  mount_uploader :profile_photo, ProfilePhotoUploader
end

Also, side note, if you're using Heroku it won't save pictures since it's a static service. You need to integrate a service like Cloudinary with Carrierwave.


After your form line <%= simple_form_for @pet, html: { multipart: true } do |f| %> put this in

<% if @pet.errors.any? %>
<div id="error_explanation">
  <h2><%= pluralize(@pet.errors.count, "error") %> prohibited this pet from being saved:</h2>

  <ul>
  <% @pet.errors.full_messages.each do |message| %>
    <li><%= message %></li>
  <% end %>
  </ul>
</div>
<% end %>

and this line <%= f.input :profile_photo, type: :file %> to this <%= f.file_field :profile_photo %>


At the end of your pet_controller's file make sure you've given permission for the form to submit the data

def pet_params
  params.require(:pet).permit(:name, :profile_photo)
end

Since I see you're using devise you might consider assigning the owner to the pet. Consider the line in your pet_controller.rb

def create
  @pet = Pet.new(pet_params)
  @pet.owner = current_user

And see the line in model belongs_to :owner

Upvotes: 1

Related Questions