All threads / Creating nested attribute with two parent attribute.

Ask A Question

Notifications

You’re not receiving notifications from this thread.

Creating nested attribute with two parent attribute.

Ariff Munshi asked in Rails

Hi,

Been going round in circles for a day or so but still can't seem to find a solution for this. I have project management chat app that on sign up, you create the project and the first chat message too. Here is my code:

user.rb

class User < ApplicationRecord
  has_many :projects, inverse_of: :user, dependent: :destroy
  has_many :messages, as: :message_owner, dependent: :destroy

  accepts_nested_attributes_for :projects

  validates :email, presence: true
  validates :password, presence: true
  validates_associated :projects
end

project.rb

class Project < ApplicationRecord

  has_many   :messages, inverse_of: :project, dependent: :destroy
  belongs_to :user, inverse_of: :projects

  accepts_nested_attributes_for :messages

  validates :name, presence: true
end

message.rb

class Message < ApplicationRecord
  belongs_to :project, inverse_of: :messages
  belongs_to :message_owner, polymorphic: true

  default_scope { order(:created_at) }

  validates :body, presence: true
end

registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  def new
    build_resource({})
    self.resource.build_user_profile
    project = self.resource.projects.new
    project.messages.new
    respond_with self.resource
  end

  def create
    super
  end

  private
    def sign_up_params
      params.require(resource_name).permit(:email,
                                            { user_profile_attributes: [:name],
                                              projects_attributes: [:name, :material, messages_attributes: [:body]]
                                            })
    end
end

new.html.haml

  = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
    / Fields for project
    = f.fields_for :projects do |project|
      .field
        = project.label :name, "Project Name"
        = project.text_field :name
      / Fields for message
      = project.fields_for :messages do |message|
        .fields
          = message.label :body, "Your Message"
          = message.text_area :body
    / Fields for user registration
    .field
      = f.label :email
      = f.email_field :email
    .actions
      = f.submit "Sign up"

I get the error that there is no associated message_owner (user). I know that this is because the fields_for is with respect to the project and has no knowledge of the user.

The problem comes as I can only associate the message with either one (project) of the other (user) but not both. I have tried creating messages as a nested attribute of user but this results in the problem of no associated project. I've tried initialising the message with a user in the registrations_controller#new but this does not seem to register either.

Could this be solved with a before_save callback in message.rb? But this will need to ensure that both the user and project are already created.

Hope someone can help. Thanks!

Managed to solve it after much tinkering. If anyone has the same problem, I called a before_validation to associate the message with the project in user.rb.

private
    def set_project
      self.messages.first.project = self.projects.first
    end

Also changed messages to be a nested attribtue to user from projects

Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 33,665+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2020 GoRails, LLC. All rights reserved.