简体   繁体   中英

Rails 4 - Carrierwave image not uploading

UPDATE : Thanks everyone for the help in trying to figure this out. I decided to give up trying to learn and added another image attribute to the profile model. This will have to do for now.

Im trying to make an app in rails 4.

I have a user model, which has an avatar attribute on it.

I also have a profile model.

User :has one profile Profile :belongs to User

The reason I split them is because profile contains all the variables and user contains all the fixed attributes that cannot be changed without admin permission.

The exception is that my user model has an avatar (image) attribute which I want to allow users to change.

I have user carrierwave in other parts of my code and it works. However, something is wrong in this use case.

I have an avatar uploader with:

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 :preview do
    process :resize_to_fill => [90,90]
  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

In my user model i have:

class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
end

In my user controller - I whitelist the :avatar in strong params.

In my profile controller strong params I've tried adding:

params.require(:profile).permit(:title, :overview, user_attributes: [:avatar])

And I have also tried allowing user attributes in my profile model (as follows):

belongs_to :user
accepts_nested_attributes_for :user

I have a partial form in my views users folder.

<%= simple_fields_for :user,  html: { multipart: true } do |f| %>
  <%= f.error_notification %>
  <div class="form-inputs">
    <%= f.input :avatar, as: :file, :label => "Add a profile image (head shot)" %>
  </div>
<% end %>

That partial is included in my profiles form.

I then want to display the user avatar in my profile show view as:

<div class="col-md-5 col-lg-4 vc-photo" style= "background-image: url(<%= image_url @profile.user.avatar.url if @profile.user.avatar? %>);">&nbsp;</div>

However, it just renders a blank.

I tried:

);">

but it still just renders blank.

Can anyone see what I've done wrong?

When i try to test in the rails console by checking the user.avatar, I get this:

u.avatar => #, last_sign_in_ip: #, confirmation_token: "73abb47df224dbc3a612b46ced66e1aba...", confirmed_at: "2016-04-02 07:13:57", confirmation_sent_at: "2016-04-02 22:59:44", unconfirmed_email: "testiest@gmail.com", failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2016-04-02 07:13:57", updated_at: "2016-04-02 22:59:43", avatar: nil, approved: false>, @mounted_as=:avatar>

TAKING THE SUGGESTION BELOW

I change my forms so that profile form now has:

<%= simple_fields_for :user,  html: { multipart: true } do |ff| %>
  <%= f.error_notification %>

              <div class="form-inputs">


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

              </div>


        <% end %>

The users/profileimgform now has:

 <%= simple_fields_for :user, html: { multipart: true } do |ff| %> <%= f.error_notification %> <div class="form-inputs"> <%= ff.input :avatar, as: :file, :label => "Add a profile image (head shot)" %> </div> <% end %> 

I'm not sure whether I need to incorporate the 'ff' into the line in my profile form. I tried replacing the last 'f' with 'ff' but got an error asking me whether it should be a single 'f'.

When I try this, the console still shows that the user.avatar is 'nil'.

I guess you have error with this code:

<%= simple_fields_for :user,  html: { multipart: true } do |f| %>
  <%= f.error_notification %>
  <div class="form-inputs">
    <%= f.input :avatar, as: :file, :label => "Add a profile image (head shot)" %>
  </div>
<% end %>

Look at html that is generated. I think there should be something like this:

<%= simple_form_for :profile do |f| %>
  ...
  <%= f.simple_fields_for :user do |ff| %>
    <%= ff.input :avatar %>
  <% end %>
<% end %>

Notice that nested form or complex form should connect model and association with form_for and fields_for helper, like this:

<%= form_for @person do |f| %>
  Addresses:
  <ul>
    <%= f.fields_for :addresses do |addresses_form| %>
      <li>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>
      </li>
    <% end %>
  </ul>
<% end %>

The way to connect between model and associations is

  • form_for @person builds person form instance f
  • use person form instance f to build association form f.fields_for :addresses instance addresses_form
  • use association form input to upload file addresses_form.input ...

Last, I guess simple_fields_for as extra helpers of simple_form, perhaps it only works for form_for helper.


Here is a example for given models and controllers:

app/models/user.rb

class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
  has_one :profile
end

app/models/profile.rb

class Profile < ActiveRecord::Base
  belongs_to :user
  accepts_nested_attributes_for :user
end

Actually, there's two ways to modify model's nested attributes.

  1. Modify the model and the nested attributes at the same form

You should build a complex form with both of your model and associations

More info: http://guides.rubyonrails.org/form_helpers.html#building-complex-forms

app/controllers/profile_controller.rb

class ProfileController < ApplicationController

  private

  def profile_params
    params.require(:profile).permit(:title, user_attributes: [:avatar])
  end
end

app/views/profile/edit.html.erb

<%= form_for :profile do |f| %>
  Avatar:
  <ul>
    <%= f.fields_for :user do |uf| %>
      <li>
        <%= uf.label :avatar %>
        <%= uf.file_field :avatar %>
      </li>
    <% end %>
  </ul>
<% end %>
  1. Modify the nested attributes only

You could build a normal form just for that association attribute, but it's tricky and vague when you have to initialize it, so I rather not to provide sample code here than confusing you.

我通过将头像从用户移动到个人资料来解决问题。

I had the same error. If you're on a mac, try installing imagemagik again. I used homebrew. You just need to run this command:

brew install imagemagick

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM