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

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

ただいまの
回答率

88.37%

FormDataでファイルをPOSTした際、paramsで値が受け取れない

解決済

回答 1

投稿

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

mitibatta

score 5

rails,vue.js初学者です。

前提・実現したいこと

railsのAPIサーバとVue.jsを使用して、FormDataを使用して画像ファイルや動画ファイルをaxiosでPOSTしたい。

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

vue側でFormDataを使用しそれぞれ、image,video,text,user_idをappendしてaxiosでPOSTした際にrailsサーバで以下のようなエラーが発生する。

Started POST "/api/posts" for ::1 at 2020-03-15 17:49:34 +0900
Processing by Api::PostsController#create as JSON
  Parameters: {"image"=>#<ActionDispatch::Http::UploadedFile:0x00007f88d80bab68 @tempfile=#<Tempfile:/var/folders/sd/cjky7p2d1_vg464prg9nx89h0000gn/T/RackMultipart20200315-44329-dppqtn.jpeg>, @original_filename="Award、優勝・受賞の無料アイコン素材 1.jpeg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"image\"; filename=\"Award\xE3\x80\x81\xE5\x84\xAA\xE5\x8B\x9D\xE3\x83\xBB\xE5\x8F\x97\xE8\xB3\x9E\xE3\x81\xAE\xE7\x84\xA1\xE6\x96\x99\xE3\x82\xA2\xE3\x82\xA4\xE3\x82\xB3\xE3\x83\xB3\xE7\xB4\xA0\xE6\x9D\x90 1.jpeg\"\r\nContent-Type: image/jpeg\r\n">, "video"=>#<ActionDispatch::Http::UploadedFile:0x00007f88d80ba988 @tempfile=#<Tempfile:/var/folders/sd/cjky7p2d1_vg464prg9nx89h0000gn/T/RackMultipart20200315-44329-jv9gni.mp4>, @original_filename="neco03_720.mp4", @content_type="video/mp4", @headers="Content-Disposition: form-data; name=\"video\"; filename=\"neco03_720.mp4\"\r\nContent-Type: video/mp4\r\n">, "user_id"=>"1", "text"=>"ttt"}
Completed 400 Bad Request in 0ms (ActiveRecord: 0.0ms | Allocations: 124)



ActionController::ParameterMissing (param is missing or the value is empty: post):

app/controllers/api/posts_controller.rb:64:in `post_params'
app/controllers/api/posts_controller.rb:20:in `create'

該当のソースコード

def create
    binding.pry
    @post = Post.new(post_params)
    @post.pictures.build(image: params[:post][:image], video: params[:post][:video], user_id: params[:post][:user_id])
    @post.pictures.each do |picture|
      picture.post_id = @post.id
    end
    if @post.text.blank?
      response_bad_request
    elsif @post.save
      response_success("投稿")
    else
      response_internal_server_error
    end
  end
             .
             .
             .
private
def post_params
    params.require(:post).permit(:text, :user_id)
  end
<template>
  <div class="user-new-wrapper">
  <div class="container">
    <div class="row">
      <div class="col-md-offset-4 col-md-4 form_box">
        <h1>投稿する</h1>
        <p v-show="errored">投稿に失敗しました。</p>
      <form @submit.prevent="createPost">
        <div class="form-group">
          <label for="image">画像</label>
          <input type="file" name="image" id="image" accept=".jpg, .jpeg, .gif, .png" @change="selectedImage">
        </div>
        <div class="form-group">
          <label for="video">動画</label>
          <input type="file" name="video" id="video" accept=".mp4" @change="selectedVideo">
        </div>
        <div class="form-group">
          <label for="text">テキスト</label>
          <textarea rows="6" cols="18" id="text" name="text" class="form-control form-text" v-model='post.text'></textarea>
        </div>
        <input type="submit" value="投稿" class="btn-block btn-white" v-if="post.logged_in > 0">
      </form>
      </div>
    </div>
  </div>
</div>
</template>

<script>
import axios from 'axios'

const hostName = 'localhost:3000'
const path = '/api/posts'

export default {
  name: 'postNew',
  data: function () {
    return {
      post: {
        uploadImage: null,
        uploadVideo: null,
        text: '',
        logged_in: 0
      },
      errored: false,
      res: {
        message: ''
      }
    }
  },
  created: function () {
    this.post.logged_in = this.$localStorage.get('loginUser')
  },
  methods: {
    selectedImage (e) {
      e.preventDefault()
      let files = e.target.files
      this.post.uploadImage = files[0]
      console.log(this.post.uploadImage)
    },
    selectedVideo (e) {
      e.preventDefault()
      let files = e.target.files
      this.post.uploadVideo = files[0]
      console.log(this.post.uploadVideo)
    },
    createPost () {
      var formdata = new FormData()
      formdata.append('image', this.post.uploadImage)
      formdata.append('video', this.post.uploadVideo)
      formdata.append('user_id', this.post.logged_in)
      formdata.append('text', this.post.text)
var config = {
        headders: {
          'content-type': 'multipart/form-data'
        }
      }
      axios.post(`http://${hostName}${path}`,
        formdata, {config}).then((result) => {
        this.$router.push('/')
        this.res = result.data
        this.$emit('flash', (this.res.message))
      }).catch(error => {
        console.log(error)
        this.errored = true
      })
    }
  }
}
</script>

試したこと

binding.pryでparams[:post]の値を調べて見るとnilと表示された。原因はこれで間違いないが、なぜ値が入らないのか分からない。

@postのストロングパラメータを消してPOSTしてみたが、
NoMethodError (undefined method `[]' for nil:NilClass):
というエラーが表示された。これも、params[:post]に値が入っていないから起こるエラーらしい。

3日ほどここに悩まされています。
どうか回答よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

原因はこれで間違いないが、なぜ値が入らないのか分からない。

FormDataへの値の追加の際に、キーをpost[image]のような形にしてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/17 17:22

    本当にありがとうございます!!

    キャンセル

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

  • ただいまの回答率 88.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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