Search code examples
ruby-on-railsnested-attributesbelongs-to

rails multiple belongs_to assignments with nested attributes


My problem is that how to assign multiple belongs_to associations with nested attributes?

I want to build a issue system. When I create a issue, I also want to create the first comment as the issue body.

So, I have following Models:

class Issue < ActiveRecord::Base
  has_many :comments, as: :commentable

  validates :title, presence: true

  accepts_nested_attributes_for :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :commentable, polymorphic: true

  validates :content, :user, presence: true
end

and I have the IssuesController as follow:

class IssuesController < ApplicationController
  before_action :authenticate_user! #devise authentication

  def new
    @issue = Issue.new
    @issue.comments.build
  end

  def create
    @issue = Issue.new(issue_params)
    @issue.save
  end

  private

  def issue_params
    params.require(:issue).permit(:title, comments_attributes: [:content])
  end
end

and the following is my form (using slim template with simple_form and nested_form gems):

= simple_nested_form_for @issue do |f|

  = f.input :title

  = f.fields_for :comments do |cf|
    = cf.input :content

  = f.button :submit

In this case, I don't know how to assign current_user to the comment created by nested attributes.

Any suggestions or other approaches? Thanks!


Solution

  • As I wrote in the comments, there's two ways of doing this. The first way is to add a hidden field in your subform to set the current user:

    = simple_nested_form_for(@issue) do |f|
      = f.input :title
      = f.fields_for(:comments) do |cf|
        = cf.input(:content)
        = cf.hidden(:user, current_user)
      = f.submit
    

    If you do not trust this approach in fear of your users fiddling with the fields in the browser, you can also do this in your controller.

    class IssuesController < ApplicationController
      before_action :authenticate_user! #devise authentication
    
      def new
        @issue = Issue.new
        @issue.comments.build
      end
    
      def create
        @issue = Issue.new(issue_params)
        @issue.comments.first.user = current_user
        @issue.save
      end
    
      private
    
      def issue_params
        params.require(:issue).permit(:title, comments_attributes: [:content])
      end
    end
    

    This way you take the first comment that is created through the form and just manually assign the user to it. Then you know for the sure that the first created comment belongs to your current user.