質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Ruby on Rails

    7479questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

  • Devise

    252questions

    Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

  • ファイル

    174questions

    ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

devise で画像を登録できない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,279

前提・実現したいこと

rails で devise を使い、名前とメールと画像を登録できるようにしたい。
しかし、画像ファイルやファイル名がうまく登録できない。

発生している問題・エラーメッセージ

エラーは出ないが思ったような動作をしてくれていない。
rails cで User.lastを見ると付け加えたimageカラムに「<ActionDispatch::Http::UploadedFile・・・」とヘンテコなファイル名が入っているし。こんな変なファイル名じゃない!

実際の画像ファイル名も、「RackMultipart20160409-5687-fplocs.jp」だとか勝手に変な名前になって、しかも入れたいフォルダ(public/user_images)に入っていない。Gemfileの隣に保存されているんだ・・・

さっぱり何だか、分からない。。。

###該当のソースコード

gemfile

source 'https://rubygems.org'

gem 'rails',        '4.2.2'
gem 'sass-rails',   '5.0.2'
gem 'uglifier',     '2.5.3'
gem 'coffee-rails', '4.1.0'
gem 'jquery-rails', '4.0.3'
gem 'turbolinks',   '2.3.0'
gem 'jbuilder',     '2.2.3'
gem 'sdoc',         '0.4.0', group: :doc

gem 'devise'
gem 'devise-bootstrap-views'
gem 'devise-i18n'
gem 'devise-i18n-views'

gem 'honoka-rails', '>= 3.3.6.3'


group :development, :test do
  gem 'sqlite3',     '1.3.9'
  gem 'byebug',      '3.4.0'
  gem 'web-console', '2.0.0.beta3'
  gem 'spring',      '1.1.3'
end

group :production do
  gem 'pg',             '0.17.1'
  gem 'rails_12factor', '0.0.2'
end

users_controller.rb です。

class UsersController < ApplicationController

  before_action :authenticate_user!
  before_action :set_user, only: [:show, :edit, :update]

  def index
   @users = User.all
  end

  def show
  end

  def new
    @user = User.new
  end

    **def create
    @user = User.new(user_params)
    # アップロードされる画像をparams[:user][:image]で受け取り変数fileに代入してください
    file = params[:user][:image]
     if !file.nil?
      file_name = file.original_filename
      # 保存先を指定してください
      File.open('public/user_images/#{file_name}', 'wb'){|f| f.write(file.read)}
      # @userのimageセッターを使って、file_nameをセットしてください
      @user.image = file_name
      @user.save
      if @user.save
      redirect_to @user, notice: 'ユーザーが保存されました'
      else
      render :new
      end
     end
    end**

    private

    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:name, :email)
    end

end

あと、views/devise/registrations/new.html.erb です。

<%= bootstrap_devise_error_messages! %>
<div class="panel panel-default devise-bs">
  <div class="panel-heading">
    <h4><%= t('.sign_up', :default => "Sign up") %></h4>
  </div>
  <div class="panel-body">
    <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { role: "form" }) do |f| %>

      <div class="form-group">
        <%= f.label '名前' %>
        <%= f.text_field :name, autofocus: true, class: "form-control" %>
      </div>



      <div class="form-group">
        <%= f.label :email %>
        <%= f.email_field :email, autofocus: true, class: "form-control" %>
      </div>
      <div class="form-group">
        <%= f.label :password %><br />
        <%= f.password_field :password, class: "form-control" %>
      </div>
      <div class="form-group">
        <%= f.label :password_confirmation %>
        <%= f.password_field :password_confirmation, class: "form-control" %>
      </div>

**        プロフィール画像
       <%= f.file_field :image, class: "form-control image-field" %>**

      <%= f.submit t('.sign_up', :default => "Sign up"), class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
<%= render "devise/shared/links" %>

---
そして、application_controller.rb
---
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

    include ApplicationHelper

  private

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << :name
**    devise_parameter_sanitizer.for(:sign_up) << :image**
  end 

end

routes.rb です

Rails.application.routes.draw do
  resources :notes
  get '/top' => 'home#top'
  get '/about' => 'home#about'

  devise_for :users
  resources :users,only:[:index,:show,:edit,:update]
  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

  # You can have the root of your site routed with "root"
  root 'home#top'

  # Example of regular route:
  #   get 'products/:id' => 'catalog#view'

  # Example of named route that can be invoked with purchase_url(id: product.id)
  #   get 'products/:id/purchase' => 'catalog#purchase', as: :purchase

  # Example resource route (maps HTTP verbs to controller actions automatically):
  #   resources :products

  # Example resource route with options:
  #   resources :products do
  #     member do
  #       get 'short'
  #       post 'toggle'
  #     end
  #
  #     collection do
  #       get 'sold'
  #     end
  #   end

  # Example resource route with sub-resources:
  #   resources :products do
  #     resources :comments, :sales
  #     resource :seller
  #   end

  # Example resource route with more complex sub-resources:
  #   resources :products do
  #     resources :comments
  #     resources :sales do
  #       get 'recent', on: :collection
  #     end
  #   end

  # Example resource route with concerns:
  #   concern :toggleable do
  #     post 'toggle'
  #   end
  #   resources :posts, concerns: :toggleable
  #   resources :photos, concerns: :toggleable

  # Example resource route within a namespace:
  #   namespace :admin do
  #     # Directs /admin/products/* to Admin::ProductsController
  #     # (app/controllers/admin/products_controller.rb)
  #     resources :products
  #   end
end

rake routesです。

Prefix Verb   URI Pattern                    Controller#Action
                   notes GET    /notes(.:format)               notes#index
                         POST   /notes(.:format)               notes#create
                new_note GET    /notes/new(.:format)           notes#new
               edit_note GET    /notes/:id/edit(.:format)      notes#edit
                    note GET    /notes/:id(.:format)           notes#show
                         PATCH  /notes/:id(.:format)           notes#update
                         PUT    /notes/:id(.:format)           notes#update
                         DELETE /notes/:id(.:format)           notes#destroy
                     top GET    /top(.:format)                 home#top
                   about GET    /about(.:format)               home#about
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
       user_registration POST   /users(.:format)               devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
                         PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                   users GET    /users(.:format)               users#index
               edit_user GET    /users/:id/edit(.:format)      users#edit
                    user GET    /users/:id(.:format)           users#show
                         PATCH  /users/:id(.:format)           users#update
                         PUT    /users/:id(.:format)           users#update
                    root GET    /                              home#top

参考にしたのはpurogateという学習サイトです。
最近有料になったので、掲載が難しいです。
http://prog-8.com/lessons/rails/intermediate

railsの中級の一番最後にプロフィール画像を載せようってのがありまして、それをしました。

ただし、中級の学習ではdevise は使っていません。

イメージは、サイトへの会員登録の際に、自分の画像を登録できるようにしたいのです。

SNSでよくある自分流の画像の登録です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • suzukis

    2016/04/10 10:41

    コードの部分は、```(バッククオート3つ)で囲むと見やすくなります。コードの部分を選択してエディタの"</>"を押してもいいです。

    キャンセル

  • M8KzBFdJPyD1kKd

    2016/04/10 10:56

    suzukisさん ありがとう! コードがかっこよくなりました!

    キャンセル

  • suzukis

    2016/04/10 11:50

    config/routes.rbの内容と、rake routesの実行結果を追記してもらえますか?後何か参照しているサイトがあればその情報と。

    キャンセル

  • M8KzBFdJPyD1kKd

    2016/04/10 12:10

    routes & rake routesの結果 載せました! 質問本文にも書きましたが、参考サイトはpurogateとか言うサイトの「rails 中級 の一番最後の章」ですが、最近有料になり、見れないと思います。 http://prog-8.com/lessons/rails/intermediate

    キャンセル

回答 1

checkベストアンサー

+1

rake routesで

user_registration POST   /users(.:format)               devise/registrations#create


となっているとおり、呼ばれているのはDeviseの標準のコントローラで、Usersコントローラは呼ばれていません。<ActionDispatch::Http::UploadedFile:...>はアップロードされたファイルを扱うオブジェクトですが、これがparam[:user][:image]に格納されていて、これをそのままモデルに渡っているので、imageカラムにはオブジェクトの文字列表現が保存されることになります。

RackMultipart20160409-5687-fplocs.jpはアップロードされたファイルが保存されている一時ファイルですが、これががアプリケーションのルートに保存されるのはよくわからないです。/tmpにできるはずなのですが。

やりたいことを実現するには、

が考えられます。前者はDeviseのドキュメントを参考にしてもらうとして、後者ですが、まず、カラムとフォームのフィールド名が一緒だと都合が悪いので、別のものに変更してください。ここではフィールド名を:image_dataにしたとして説明します。

class User << ActiveRecord::Base
  def image_data=(file)
    self.image = save_file(file)
  end

  def image_data #画像の読み込み
    open(self.image).read
  end

  private 
  def save_file(file)
    file_name = file.original_filename
    File.open('public/user_images/#{file_name}', 'wb'){|f| f.write(file.read)}
    file_name
  end
end

こんな感じですかね。これだとimage_dataにデータを渡したタイミング(@users.image_data = dataしたタイミング)で保存が走ります。あまり頻繁に保存するのが都合が悪ければafter_saveあたりのコールバックで保存するようにしてください。

あと、ファイル名のチェックを入れてください。".."や"/"などが含まれていると良くないことが起きます。渡されたファイル名ではなく、idを使っても良いでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/10 14:41

    suzukisさん、素早いご回答ありがとうございます!

    きちんと理解するために、じっくりと書き込みされた内容を見つめさせていただきます。

    初心者なので、すっと頭に入りませんw

    せっかくなので、咀嚼して、噛みしめて理解し、実行したいと思います。

    取り急ぎ、お礼のコメントを書かせてもらいました!

    色々とありがとうございます。

    また、私rails 勉強して、やっと少しづつ、書けるようになっている自分を感じて、楽しいところです!!!

    今後ともよろしくお願いします!

    キャンセル

  • 2016/04/10 17:32

    よし、前者の「Deviseのコントローラをカスタマイズする」、英語なので後回しにして
    後者の「コントローラではなくモデル側でファイルを扱う」で解決を目指します!

    で、さっそく躓くw

    「カラムとフォームのフィールド名が一緒だと都合が悪いので」の箇所

    意味が・・・OTZ

    カラムって言えば、usersデーターベースで言うところの、name,email,imageかな??

    でもって、フォームのフィールド名って言うものは

    views/devise/registrations/new.html.erbの中の
    ** プロフィール画像
    <%= f.file_field :image, class: "form-control image-field" %>**

    ↑のimageのことですかい?

    と解釈し、

    <%= f.file_field :image_data, class: "form-control image-field" %>

    にしてみます。

    そして、そして、suzukisさんに書いていただいた、User モデルを 書き加えてみます!

    ```
    class User < ActiveRecord::Base

     def image_data=(file)
    self.image = save_file(file)
    end

    def image_data #画像の読み込み
    open(self.image).read
    end

    has_many:notes
    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :registerable,
    :recoverable, :rememberable, :trackable, :validatable

    validates :name,uniqueness: true



    private

    def save_file(file)
    file_name = file.original_filename
    File.open('public/user_images/#{file_name}', 'wb'){|f| f.write(file.read)}
    file_name
    end

    end

    ```

    キャンセル

  • 2016/04/10 17:46

    まずはdeviseとは関係ないモデルでやってみるといいですよ

    キャンセル

  • 2016/04/10 19:01

    def image_data=(file)
    self.image = save_file(file)
    end

    のとこで次の2つのエラーマークが出ます。

    1つめ
    warning:assigned but unused variable-image_date
    警告:割り当てられたが、使っていない可変的なimage_date

    2つめ
    warning:mismatched indentations at 'end' with 'class' at 1
    警告:『クラス』が1時にある『終わり』の不釣合いなインデント

    ということで、私なりに修正

    def image_data(file)
    self.image = save_file(file)
    end

    最初のエラーは消えるけど、2つめのエラーが残ったまま・・・

    そして、コード最後のendにもcloud9エディタにエラーマーク

    syntax error,unexpected keyword_end,expecting end-of-input


    うーん(゜-゜) 動かない

    devise とは関係ないモデルでやってみようかな・・・

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Ruby on Rails

    7479questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

  • Devise

    252questions

    Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

  • ファイル

    174questions

    ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。