Rails file_field tag передает только имя файла String контроллеру

Мой тег file_field передает только имя файла, а не сам файл контроллеру.

В моей модели User:

mount_uploader :avatar, AvatarUploader
validate :avatar_size
...
def avatar_size
  errors.add :avatar, "should be less than 5MB" if avatar.size > 5.megabytes
end

AvatarUploader:

class AvatarUploader < CarrierWave::Uploader::Base

  include CarrierWave::MiniMagick
  process resize_to_limit: [50, 50]

  if Rails.env.production?
    storage :fog
  else
    storage :file
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def extension_white_list
    %w(jpg, jpeg, gif, png)
  end

end

И пользовательский контроллер:

before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:destroy]
skip_before_action :verify_authenticity_token, only: [:create]
...
def update
  @user = User.find(params[:id])
  if @user.update_attributes user_params
    flash[:success] = "Profile updated"
    redirect_to user_path @user
  else
    render 'edit'
  end
end
...
def user_params
  params.require(:user).permit :name, :email, :password, :password_confirmation, :avatar
end

def correct_user
  @user = User.find params[:id]
  redirect_to root_path unless @user == current_user
end

def admin_user
  redirect_to root_path unless current_user.admin?
end

Форма в виде:

<%= form_for(@user) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label :email %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <% if @user.avatar? %>
    <%= image_tag @user.avatar.url, size: "50x50" %>
  <% else %>
    <%= image_tag "stock_ava.png", size: "50x50" %>
  <% end %>

  <%= f.file_field :avatar, accept: 'image/jpeg,image/gif,image/png' %>

  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

В консоли я вижу атрибут "FinnJake.png", а не соответствующий ActionDispatch.

Processing by UsersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"h9tD/g2M1zJ5L4cnysIQwHCWxDdhhhJR1I9a9+FAWeT9aTXPte16Uyn8GvI4w23klfvYtTaLCDrGVonHfmFUag==", "user"=>{"name"=>"Example User", "email"=>"example@user.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "avatar"=>"FinnJake.png"}, "commit"=>"Save Changes", "id"=>"1"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   (0.1ms)  begin transaction
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ?  [["email", "bexample@user.com"], ["id", 1], ["LIMIT", 1]]
  SQL (1.1ms)  UPDATE "users" SET "avatar" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["avatar", nil], ["updated_at", "2017-10-02 14:50:41.226691"], ["id", 1]]
   (142.3ms)  commit transaction
Redirected to https://rubyonrails-xxx.c9users.io/users/1
Completed 302 Found in 155ms (ActiveRecord: 144.1ms)

Я очень плохо знаком с рельсами, но не могу понять, почему file_field не загружает файл. Я могу видеть в браузере, что я в конечном итоге с этим тегом:

<input accept="image/jpeg,image/gif,image/png" type="file" name="user[avatar]" id="user_avatar">

Который выглядит правильным для меня. Я также не могу вручную обновить этот столбец через консоль rails, хотя я не получаю ошибок:

2.4.0 :002 > user = User.first
  User Load (0.5ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => #<User id: 1, name: "Example User", email: "example@user.com", created_at: "2017-10-02 14:32:22", updated_at: "2017-10-02 16:35:55", password_digest: "$2a$10$sww7gItks0mYz6xz8zV.QOIjr6to/o5Jytjmuo0wxny...", remember_digest: nil, admin: true, activation_digest: "$2a$10$W396r7A8aZaii3DC7b3W7u70etSmXh3MORMIoWtcSHo...", activated_at: "2017-10-02 14:32:22", reset_digest: nil, reset_sent_at: nil, avatar: nil> 
2.4.0 :003 > user.update avatar: "String"
   (0.2ms)  begin transaction
  User Exists (0.4ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ?  [["email", "example@user.com"], ["id", 1], ["LIMIT", 1]]
  SQL (2.4ms)  UPDATE "users" SET "updated_at" = ?, "avatar" = ? WHERE "users"."id" = ?  [["updated_at", "2017-10-02 17:27:06.097363"], ["avatar", nil], ["id", 1]]
   (11.4ms)  commit transaction
 => true 

Заранее спасибо за любой совет, который вы можете предоставить.

2 ответа

Вы должны использовать многочастную форму как:

form_for(@user, html: { multipart: true }) do ...

Смотрите http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html

Нашел проблему. Смотрите этот комментарий

По сути, форма в части была обернута другой формой, которая имела другой тип кодирования.

Другие вопросы по тегам