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

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

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

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

2回答

2434閲覧

Rails:fields_forを使って関連先のテーブルへアップロードされたファイルを保存する方法

Uchikoba

総合スコア16

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2015/09/17 05:53

Railsにお詳しい方のお知恵をお借しください……

親テーブル(workitems)の編集フォームからアップロードされたファイルを、
子テーブル(destination)へ保存しようとしているのですが、なかなか上手く行きません。

アップロードされるファイルはCSV(text/csv)のみです。

paperclipが有効という情報を見つけ、あちこち参考にしつつ試したのですが、
「contenttypeが不正」というエラーが回避できず……

仕方なく自力でbinary型の列へ保存する方法を行おうとしてるのですが、
こちらでも躓いてしまい途方に暮れております。

Model(~/app/models/workitem.rb , ~/app/models/destination.rb)

lang

1class Workitem < ActiveRecord::Base 2 # rails g scaffold workitem name:string 3 has_one :destination, :dependent => :destroy 4 accepts_nested_attributes_for :destination 5end 6 7class Destination < ActiveRecord::Base 8 # rails g model destination name:string workitem_id:integer upload_file:binary 9 belongs_to :workitem 10end

View(~/app/views/workitems/_form.html.erb)

lang

1<%= form_for @workitem, multipart: true do |f| %> 2 <%= f.fields_for @workitem.destination do |dest_f| %> 3 <%= dest_f.file_field :upload_file %> 4 <% end %> 5<% end %>

Controller(~/app/controllers/workitems_controller.rb)

lang

1class WorkitemsController < ApplicationController 2 def new 3 @workitem = Workitem.new 4 @workitem.build_destination 5 end 6 7 def create 8 # あれこれ試してみて自力でパラメータを作ればどうにかなるかと以下のコードを書きました 9 10 # workitem_paramsを退避。ファイルがアップロードされなければ 11 # こいつがこのまま使用されるので問題ないはず 12 temp_workitem_params = workitem_params 13 destination_attributes = workitem_params[:destination_attributes] 14 upload_file = destination_attributes[:upload_file] 15 # => ActionDispath::Http::UploadedFile 16 17 if upload_file != nil 18 # ファイルがアップロードされてれば 19 if @workitem.destination != nil 20 # 既存のアップロードファイルがあれば消す 21 @workitem.destination.destroy 22 end 23 24 # アップロードされたファイルの情報をworkitem_param[:destination_attributes]に仕込む 25 content = {} 26 content[:filename] = upload_file.original_filename 27 content[:upload_file] = upload_file.read 28 29 temp_workitem_params.delete('destination_attributes') 30 temp_workitem_params['destination_attributes'] = content 31 end 32 33 @workitem = Workitem.new(temp_workitem_params) 34 respond_to do |format| 35 if @workitem.save 36 # この中身はそのまま 37 end 38 end 39 end 40 41 def update 42 # create と同じく、workitem_paramsからDispatch::Http::UploadedFileの情報を展開し、 43 # destination_attributesの中身を差し替えて@workitem.updateを行っています 44 end 45 46 private 47 def workitem_params 48 params.require(:workitem).permit(:name, destination_attributes: [ :upload_file, :filename, :workitem_id ]) 49 end 50end

上記のような構成にてデータの更新を行おうとすると、
ActiveModel::ForbiddenAttributesError という例外が発生してしまいます。

ストロングパラメータはテーブルのものと同じにしてあるのですが、
どこが原因なのか皆目検討もつかず……

サーバ環境は

  • CentOS 6.6
  • ruby 2.0.0p645
  • Rails 4.2.1

となっております。

workitemが登録・更新されるタイミングでファイルのアップロードも行いたいため
色々と調べてはみたのですが、これ以上はどうしもうよなく……
不足している情報があれば分かる範囲でお出ししますので、よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

自己解決

workitem_paramsから:destination_attributesだけを取り出してDestinationを登録、workitem_paramsがら:destination_attributesを消す という力技で解決いたしました。

lang

1class WorkitemsController < ApplicationController 2 def new 3 @workitem = Workitem.new 4 @workitem.build_destination 5 end 6 7 def edit 8 @workitem.build_destination unless @workitem.destination 9 end 10 11 def create 12 @destination = nil 13 14 temp_workitem_params = workitem_params 15 destination_attributes = temp_workitem_params[:destination_attributes] 16 upload_file = destination_attributes[:upload_file] 17 if upload_file != nil 18 content = {} 19 content[:filename ] = upload_file.original_filename 20 content[:upload_file] = upload_file.read 21 @destination = Destination.new(content) 22 end 23 # 後述する@workitem.saveに影響するのでdestination_attributesを削除 24 temp_workitem_params.delete('destination_attributes'); 25 26 @workitem = Workitem.new(workitem_params) 27 respond_to do |format| 28 if @workitem.save 29 if @destination 30 @destination.workitem_id = @workitem.id 31 @destination.save 32 end 33 end 34 end 35 end 36 37 def update 38 temp_workitem_params = workitem_params 39 destination_attributes = temp_workitem_params[:destination_attributes] 40 upload_file = destination_params[:upload_file] 41 if upload_file != nil 42 if @workitem.destination != nil 43 @workitem.destination.destroy 44 end 45 46 content = {} 47 content[:filename ] = upload_file.original_filename 48 content[:upload_file] = upload_file.read 49 @destination = Destination.new(content) 50 @destination.workitem_id = @workitem.id 51 @destination.save 52 end 53 # 後述する@workitem.updateに影響するのでdestination_attributesを削除 54 temp_workitem_params.delete('destination_attributes'); 55 56 respond_to do |format| 57 if @workitem.update(temp_workitem_params) 58 end 59 end 60 end 61end

なんと泥臭い……(´・ω・`)

投稿2015/09/17 10:04

編集2015/09/18 01:08
Uchikoba

総合スコア16

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

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

0

もしかして、

Ruby

1 @workitem = Workitem.new(temp_workitem_params)

のところでコケてませんか?

だとしたら、attr_acessibleの設定がないだけなのでは?

Ruby

1class Workitem < ActiveRecord::Base 2 # rails g scaffold workitem name:string 3 has_one :destination, :dependent => :destroy 4 accepts_nested_attributes_for :destination 5 attr_accessible :name 6end 7 8class Destination < ActiveRecord::Base 9 # rails g model destination name:string workitem_id:integer upload_file:binary 10 belongs_to :workitem 11 attr_accessible :upload_file, :filename 12end

こんな感じ。

投稿2015/09/17 06:40

rifuch

総合スコア1901

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

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

Uchikoba

2015/09/17 09:16

ご回答ありがとうございます。 Rails4では、attr_accessibleではなく下記のように、ストロングパラメータによるパーミッション設定を行わねばならないようでして、設定そのものはできていると思います。 ```lang-Ruby class WorkitemsController < ApplicationController private def workitem_params params.require(:workitem).permit(:name, destination_attributes: [ :upload_file, :filename, :workitem_id ]) end end ```
rifuch

2015/09/17 10:05

あ、Rails4でしたね・・・すみません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問