0
votes

I am working on a Rails project and I am using namespacing for the models and controllers. That is the child models (admin and student) are put in a directory called user and the controllers are put in a directory called users.

I also have admins_controller and students_controller that use the admin model and the student model respectively. These controllers are namespaced using users directory.

I then have a personal_info model that contains more details about the user, such as gender, age, date of birth. The personal_info table has a one-to-one relationship with the user model.

Here's my code;

Personal Info model:

class PersonalInfo < ApplicationRecord
  belongs_to :user
end

User model:

class User < ApplicationRecord
  has_secure_password
  has_one :personal_info, class_name: 'PersonalInfo', dependent: :destroy
  accepts_nested_attributes_for :personal_info, allow_destroy: true
end

Admin model:

class User::Admin < User
end

Admin Controller:

class Users::AdminsController < ApplicationController
  before_action :set_admin, only: [:show, :edit, :update, :destroy]

  # GET /admins
  # GET /admins.json
  def index
    @admins = User::Admin.all
  end

  # GET /admins/1
  # GET /admins/1.json
  def show
  end

  # GET /admins/new
  def new
    @admin = User::Admin.new
    @admin.build_personal_info
  end

  # GET /admins/1/edit
  def edit
  end

  # POST /admins
  # POST /admins.json
  def create
    @admin = User::Admin.new(admin_params)
    @admin.build_personal_info

    respond_to do |format|
      if @admin.save
        format.html { redirect_to users_admin_path(@admin), notice: 'Admin was successfully created.' }
        format.json { render :show, status: :created, location: users_admin_path(@admin) }
      else
        format.html { render :new }
        format.json { render json: @admin.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /admins/1
  # PATCH/PUT /admins/1.json
  def update
    respond_to do |format|
      if @admin.update(admin_params)
        format.html { redirect_to users_admin_path(@admin), notice: 'Admin was successfully updated.' }
        format.json { render :show, status: :ok, location: users_admin_path(@admin) }
      else
        format.html { render :edit }
        format.json { render json: @admin.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /admins/1
  # DELETE /admins/1.json
  def destroy
    @admin.destroy
    respond_to do |format|
      format.html { redirect_to users_admins_url, notice: 'Admin was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_admin
    @admin = User::Admin.find(params[:id])
  end

  # Only allow a list of trusted parameters through.
  def admin_params
    params.require(:user_admin).permit(
      :email, :password, :role_id, 
      personal_info_attributes: [ :id, :first_name, :last_name, :phone, 
                                   :gender, :dob, :address, :city, :state, 
                                   :country ]
    )
  end
end

Routes:

Rails.application.routes.draw do
  namespace :users do
    resources :admins
    resources :students
  end
end

_form.html.erb:

<% if @admin.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@admin.errors.count, "error") %> prohibited this admin from being saved:</h2>

    <ul>
      <% @admin.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

<%= fields_for :personal_info do |form| %>
  <div class="field">
    <%= form.label :first_name %>
    <%= form.text_field :first_name %>
  </div>

  <div class="field">
    <%= form.label :last_name %>
    <%= form.text_field :last_name %>
  </div>
<% end %>

<div class="field">
  <%= form.label :email %>
  <%= form.text_field :email %>
</div>

<%= fields_for :personal_info do |form| %>
  <div class="field">
    <%= form.label :phone %>
    <%= form.text_field :phone %>
  </div>
<% end %>

<div class="field">
  <%= form.label :password %>
  <%= form.text_field :password %>
</div>

<div class="actions">
  <%= form.submit %>
</div>

new.html.erb:

<h1>Editing Admin</h1>

<%= form_with(model: @admin, url: users_admins_path, local: true) do |form| %>
  <%= render partial: 'form', admin: @admin, locals: { form: form } %>
<% end %>

<%= link_to 'Back', users_admins_path %>

However, when I try to create a new admin or update an already existing admin after adding inputs to the displayed form no Personal Info data is saved on the database. They are all nil.

PersonalInfo Load (0.3ms) SELECT "personal_infos".* FROM "personal_infos" WHERE "personal_infos"."user_id" = $1 LIMIT $2 [["user_id", 6], ["LIMIT", 1]]

=> #<PersonalInfo id: 2, first_name: nil, last_name: nil, phone: nil, gender: nil, dob: nil, address: nil, city: nil, state: nil, country: nil, user_id: 6, created_at: "2020-06-26 13:37:16", updated_at: "2020-06-26 13:37:16">

I have tried to get this resolved, but no luck yet. Any form of help will be highly appreciated.

1

1 Answers

0
votes

you should call your fields_for from admin form as:

<%= form.fields_for :personal_info do |form| %>

otherwise it sends these params independent from admin, rather than nested as you'd like.

fwiw, for better reading, I would consider rename your inner personal_info form variable to not clash with admin form variable. But that's just a suggestion. :)