Search code examples
ruby-on-railsmongoidnested-attributes

Saving nested attributes in mongoid document in rails api


Im trying to have an iphone user be able to create a school and multiple admins at the same time. However when I try to save the school using nested attributes it returns the error admins is invalid

School Model

class School
    include Mongoid::Document
    include Mongoid::Timestamps

    # Callbacks
    after_create :spacial

    embeds_many :admins
    accepts_nested_attributes_for :admins
  validates_associated :admins

    # Fields
    field :school_name, type: String

end

Admin Model

class Admin
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :school

  before_create :generate_authentication_token!

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

end

Schools Controller

class Api::V1::SchoolsController < ApplicationController
    def show
        respond_with School.find(params[:id])
    end
    def create
        school = School.new(school_params)
        admin = school.admins.build
        if school.save
            render json: school, status: 201, location: [:api, school]
        else
            render json: { errors: school.errors }, status: 422
        end
    end

    private

    def school_params
        params.require(:school).permit(:school_name, admins_attributes: [:email, :password, :password_confirmation])
    end
end

Parameters

Parameters: {"school"=>{"school_name"=>"Curry College", "admins_attributes"=>{"0"=>{"email"=>"test@gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "subdomain"=>"api"}

Solution

  • Try this:

    class Api::V1::SchoolsController < ApplicationController
      def create
        school = School.new(school_params)
        if school.save
            render json: school, status: 201, location: [:api, school]
        else
            render json: { errors: school.errors }, status: 422
        end
      end
    
      private
    
      def school_params
        params.require(:school).permit(:school_name, admins_attributes: [:email, :password, :password_confirmation])
      end
    end
    

    As you have permitted admins_attributes inside your controller, they will be automatically assigned to the new Admin object when assigning school_params to School.new. You don't need to explicitly build an admin there.

    The error you are getting is because you are building an admin admin = school.admins.build but not assigning any attributes to it, so the validations fail on this Admin object. So, you can completely skip this line and try my solution above.