Rails
nested_attributes

nested_attributes_for で親クラスと子sasasas

事例

Article と というモデルがあるとする。これははそれぞれ一対多の関係を持っていて、

article.rb
has_many :comments
accepts_nested_attributes_for :comments, allow_destroy: true

comment.rb
belongs_to :article

という関係を持っている。

article を作成した時同時にcommentを作成したいと思い、このようなコントローラー設計にしている。

article_controller.rb
  def new
    @topic = Topic.new
    @topic.comments.build
  end


  def create
    @topic = Topic.new(topi_params)
    @article = current_user.articles.build(article_params)

    respond_to do |format|
      if @topic.save

        format.html { redirect_to @article }
        format.json { render :show, status: :created, location: @article }
      else
        format.html { redirect_back(fallback_location: root_path) }
        format.json { render json: @article.errors}
      end
    end
  end


    private

    def topic_params
      params.require(:topic).permit(:title, comments_attributes: [:id, :comment])
    end


しかしこの状態ならエラーが出る。

@article.errors

# =>
 @messages={:"comments.commentable"=>["translation missing: ja.activerecord.errors.models.comment.attributes.commentable.required"]}>

解決方法

こんな時、comment のリレーションに一つ付け足せばいい

  belongs_to :commentable, optional: true

そうすると保存できる.

原因

循環した矛盾が起きているのが原因だ。
Comment には belongs_to :article と書いてあるから、Topic は Comment が作成されていることが要請される。しかしCommentの`topic_id`に親のTopic のid を要請されるので、comment も Topic が作成されていることが要請される。どちらを 作るのにも、どちらか一方が作られている必要があり、循環矛盾が 発生してしまっている。 だから optional: true にして、 TOpic が作成される時、別に commentがなくてもいいよ、というようにしてやることで、 topic が無事作成され、commentもtopic_id が存在するから無事保存できる。

※ id、created_at, updated_at は保存できないと埋められない