Skip to main content

Creating nested attribute with two parent attribute.

Rails • Asked by Ariff Munshi

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


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.