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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Devise

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

ファイル

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

Ruby on Rails

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

Q&A

解決済

1回答

3991閲覧

devise で画像を登録できない

M8KzBFdJPyD1kKd

総合スコア26

Devise

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

ファイル

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

Ruby on Rails

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

0グッド

0クリップ

投稿2016/04/09 12:43

編集2016/04/10 03:06

###前提・実現したいこと

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でよくある自分流の画像の登録です。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suzukis

2016/04/10 01:41

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

2016/04/10 01:56

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

2016/04/10 02:50

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

2016/04/10 03:10

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

回答1

0

ベストアンサー

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 05:03

suzukis

総合スコア1449

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

M8KzBFdJPyD1kKd

2016/04/10 05:41

suzukisさん、素早いご回答ありがとうございます! きちんと理解するために、じっくりと書き込みされた内容を見つめさせていただきます。 初心者なので、すっと頭に入りませんw せっかくなので、咀嚼して、噛みしめて理解し、実行したいと思います。 取り急ぎ、お礼のコメントを書かせてもらいました! 色々とありがとうございます。 また、私rails 勉強して、やっと少しづつ、書けるようになっている自分を感じて、楽しいところです!!! 今後ともよろしくお願いします!
M8KzBFdJPyD1kKd

2016/04/10 08: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 ```
suzukis

2016/04/10 08:46

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

2016/04/10 10: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 とは関係ないモデルでやってみようかな・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問