2

I'm trying to make an app in Rails 4.

I use Carrierwave for file uploads.

I have two models, user & profile.

They each have:

profile.rb

mount_uploader :hero, HeroUploader

user.rb

  mount_uploader :avatar, AvatarUploader

I then have uploaders as:

Hero:

class HeroUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  process :resize_to_fit => [950, 245]
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  version :wide do
    process :resize_to_fill => [951,245]
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_white_list
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end

end

Avatar:

class AvatarUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def cache_dir
    "#{Rails.root}/tmp/uploads"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process :resize_to_fit => [50, 50]
  # end

  process :resize_to_fit => [800, 800]
  # Create different versions of your uploaded files:
  version :thumb do
    process :resize_to_fill => [200,200]
  end

  version :profile do
    process :resize_to_fill => [345,245]
  end

  version :wide do
    process :resize_to_fill => [951,245]
  end

  version :small do
    process :resize_to_fill => [35,35]
  end


  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_white_list
     %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end

end

I'm still in development mode (so not sure if that makes a difference).

In my profile form I have:

<%= simple_form_for(@profile) do |f| %>
            <%= f.error_notification %>

              <div class="form-inputs">

          <div class="intpol2">
            About you
          </div>

          <div class="row">
            <div class="col-md-4">
              <%= f.input :title,  autofocus: true %>
            </div>

            <div class="col-md-8">
              <%= f.input :occupation, :label => "Your occupation or job title" %>
            </div>

          </div>

          <div class="row">
            <div class="col-md-6">
               <%= render 'users/profileimgform', f: f %>   
            </div>

            <div class="col-md-6">
             <%= f.input :hero, as: :file, :label => "Add a background image to your profile page" %>
            </div>

          </div>

And my user partial form for the profile avatar image has:

<%= simple_fields_for :user do |f| %>
  <%= f.error_notification %>

              <div class="form-inputs">


              <%= f.input :avatar, as: :file, :label => "Add a profile image (head shot)" %>

              </div>


        <% end %>

When I save all this and try to use the form to upload images, I get two different results.

For the user avatar image, I get nothing displayed in the show page. When I inspect the element, there is an empty div container showing.

However,for the profile hero image, the show page shows a broken link image, and when I inspect the element, I get:

Failed to load resource: the server responded with a status of 404 (Not Found)

Is there another step to making this work?

My profile controller has strong params which include both of these attributes:

def profile_params
      params[:profile].permit(:user_id, :title, :hero, :overview, :research_interest, :occupation, :external_profile, 
        :working_languages, :tag_list,
          user_attributes: [:avatar]
          )
    end

Taking Alexei's suggestion below, I changed the opening line of the profiles form to:

<%= simple_form_for @profile, html: { multipart: true }  do |f| %>

When I save this and try again, I get exactly the same error as previously.

In my profiles show page, I have:

<%= image_tag '@profile.user.avatar.url.profile' if @profile.user.avatar? %>

            <%= image_tag '@profile.hero.url.wide' if @profile.hero? %> %>

These image tags are in the same show page. The avatar attribute is in the users table (profile belongs to user) and the hero attribute is in the profile table. The difference in errors is that the div tag containing the avatar just appears as blank in the code inspector. The div tag containing the hero image, appears as a broken link and shows a 404 error in the code inspector.

In my articles show page I have the same problem, but instead of rendering the image, it shows the typed name of the image file.

Mel
  • 2,481
  • 26
  • 113
  • 273

1 Answers1

1

Your code with multipart totally working, just remove quotes in image_tag:

<%= image_tag @profile.user.avatar.profile.url if @profile.user.avatar? %>

<%= image_tag @profile.hero.wide.url if @profile.hero? %>
Inpego
  • 2,657
  • 13
  • 14
  • Great. Thanks - but the image magic resize doesnt work undefined method `wide' for "/uploads/profile/hero/1/croppedplane.png":String – Mel Jan 02 '16 at 04:51
  • It's a 404 error when I add wide into that expression (even before url). If I take it out, it shows the image but without resizing it – Mel Jan 02 '16 at 05:02
  • Does file "YOUR_APP_FOLDER/public/uploads/profile/hero/1/wide_croppedplane.png" exist? If not, restart web-server and upload image again. – Inpego Jan 02 '16 at 05:13
  • Do I need to do something extra to get this working in production mode. I just tried to push this and I have to edit the profile and upload the image in production to get it to appear. – Mel Jan 02 '16 at 23:37
  • You don't need any extra to get this working on production. That image most probably was broken and everything should be working all right in the future. – Inpego Jan 04 '16 at 15:58
  • the image disappears each time i logout – Mel Jan 04 '16 at 20:14
  • 1
    Actually - I just found this article which addresses this problem https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Make-Carrierwave-work-on-Heroku – Mel Jan 04 '16 at 20:40