Rails 2つのフォームから1つのDBにデータ登録ができない
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 128
ブログ記事の投稿フォームでDBに格納したいと思っています。
DBは「ブログ本体のDB」と「カテゴリー用のDB」の2つがあります。
投稿フォームで、ブログタイトルや本文のフォームとカテゴリーを選択するフォーム、2つのフォームがあり、
カテゴリーフォームは「カテゴリー用のDB」から参照し、 collection_select
でプルダウン表示させています。
buildメソッドや accepts_nested_attributes_for
などを記述し、2つのフォームの関係性を認識させようとしましたが、
NoMethodError in BlogsController#new
undefined method `blogcategories' for nil:NilClass
@blog.blogcategories.build
とエラー表示され、うまくできません。
様々なサイトを見て同じように buildメソッド
を書いたのですがなぜこうなるのかよくわからずいまいちピンとこないので、ご指摘いただければ助かります。
また、DBの関係は1つの記事につき、1つのカテゴリーしか参照できませんが、カテゴリーからはいくつもの記事に参照できる「1対多」の関係です。
blogs_controller.rb
createアクションは手をつけていません。
def new
@blog.blogcategories.build
@dbsort = Blogcategory.new # カテゴリーの表示
end
def create
@blog = Blog.new(blog_params)
respond_to do |format|
if @blog.save
format.html { render :index }
format.json { render :show, status: :created, location: @blog }
else
format.html { render :new }
format.json { render json: @blog.errors, status: :unprocessable_entity }
end
end
end
private
def blog_params
params.require(:blog).permit(:blogtitle, :blogcategory_id, :content, blogs_attributes[:blogcategory_id])
end
/views/blogs/new.html.erb
投稿フォームのview
カテゴリーの部分はプルダウン(select)で表示させています。
<h1>ブログを投稿する</h1>
<%= form_for(@blog) do |f| %>
<% if @blogchou.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@blog.errors.count, "error") %> prohibited this blog from being saved:</h2>
<ul>
<% @blog.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field :blogtitle, placeholder: 'ブログタイトル' %>
<%= form_for @dbsort do |c| %>
<%= c.collection_select :id, Blogcategory.all, :id, :category %>
<% end %>
<%= f.text_field :content, placeholder: 'ブログの内容' %>
<%= f.submit 'ブログを投稿する' %></div>
<% end %>
/models/blogcategory.rb
カテゴリー用DBのモデル
class Blogcategory < ApplicationRecord
has_many :blogs
accepts_nested_attributes_for :blogs, allow_destroy: true
end
/models/blog.rb
ブログ本体DBのモデル
class Blog < ApplicationRecord
belongs_to :blogcategory
end
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
エラーメッセージの
undefined method `blogcategories' for nil:NilClass
は,NilClass
クラスのインスタンスである nil
に blogcategories
というメソッドは定義されていない,ということです。
とすれば,@blog
が nil
であると分かります。
BlogsController
の new
メソッドを見ると,いきなり
@blog.blogcategories.build
で始まっていますね。
before_action
などで @blog
をセットしているのでなければ,ここで初めて @blog
が出てくるのですが,「未定義のインスタンス変数の値は nil
」というルールがあるので,nil
の blogcategories
メソッドを呼び出そうとしていることになるのです。
(追記)
エラーの原因は以上ですが,new
メソッドで最初にやるべきことはおそらく
@blog = Blog.new
で空の(フォーム用の)Blog
オブジェクトを作ることでしょうね。
で,Blog
モデルの定義を見ると
belongs_to :blogcategory
なので,そもそも Blog
に blogcategories
というメソッドはありません。(複数あるはずがありませんよね)
belong_to
の解説(参考にしたもの)をもう一度よく読んでみてください。
今の場合,blogcategory
という単数形のメソッドが使えます。
ただ,new
メソッドで @blog.blogcategory.build
ってやる必要がよくわかりません。
また,フォームが入れ子になっているのもよく分かりません。
Blog
のためのフォームなので,カテゴリーを選ぶところは category_id
の値を select
させればよいと思うのですが。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 91.05%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/12/28 02:47
実はsubmitしても無反応だったためbuildあたりが怪しいからではないかと推測し、この質問をしたのですが、buildしても相変わらず無反応なため、buildではなくform_forの入れ子の部分とルーティングの仕方が原因ではないかとわかりました。
また改めて調べて実際にやってみたいと思います。
丁寧にご指摘いただきbuildについて大変参考になりました。ありがとうございました。