0

Im new to ruby on rails so i need some tips please.

Im trying to render some checkboxes on the edit view for a user. I have tried to follow the documentation for the nested_attributes but the checkboes does not render. Here is the relation between the two models:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :softwares
  has_many :courses

  accepts_nested_attributes_for :softwares
  accepts_nested_attributes_for :courses

The Edit view for a user

<div class="container">
  <div class="row">
    <div class="col-md-12 mt-5">
      <%= form_for @student, url: auth_student_path(@student), method: :put do |f| %>
      

         <div class="col-md-12 mb-5 mt-5">
            <div class="row">
                <h3 class="mb-3 filter_heading">Softwares</h3>
            

            <% @softwares.each do |sf|%>
              <%= f.fields_for :softwares do |software| %>
                <div class="col-md-3">
                  <div class="courses">
                    <%= software.label sf.title %>
                    <%= software.check_box :title, {multiple: true}, sf.title, nil %>
                  </div>

                 <% sf.courses.each do |crs|%>
                    <%= f.fields_for :courses do |course|%>
                      <div class="mt-1 courses-checkbox">
                          <%= course.label crs.name %>
                          <%= course.check_box :name, {multiple: true}, crs.name , nil %>
                      </div>
                    <% end %>
                  <% end%>
                </div>
              <% end %>
            <% end%>
          </div>
         

        <div class="form-group">
          <%= f.submit "Save", class:"btn btn-primary"%>
        </div>
      <% end %>
    </div>
  </div>
</div>

The Controller


module Auth
    class StudentsController < ApplicationController
        before_action :authenticate_user!
        before_action :set_student, only: %i[delete_certificates]

        def edit
            authorize! :edit, @user
            @softwares = Software.all
            @student = User.find(params[:id])
        end

        def update
            authorize! :update, @user
            @student = User.find(params[:id])

            if @student.update(student_params)               
                redirect_to edit_auth_student_path(@student)
            else               
                redirect_to edit_auth_student_path(@student)
            end
        end

        def show


        def set_student
            @student = User.find(params[:student_id])
        end

        private
    
        def student_params
            params.require(:user).permit(
              :email,
              :firstname,
              :lastname,
              :phone,
              :locked,
              :approved,
              :role,
              badges: [],
              certificates: [],
              softwares_attributes: [:title],
              courses_attributes: [:name],
            )
          end
    end
end
    

Please help me.

6
  • A heads up - software is uncountable so the proper plural is software. This code will work since rails doesn't have a proper inflection set up but may cause developer confusion. Commented Nov 9, 2022 at 16:16
  • To answer the specific question of why f.fields_for :softwares isn't actually rendering anything its because you haven't actually assigned anything to @student.softwares. fields_for loops through the assocation and if there is nothing to loop through then nothing happens. You're really just using it very wrong here though. Commented Nov 9, 2022 at 16:23
  • @max The problem here is that when students are created the dont have any belonging Softwares. Its only the Admin that can update the student on what Softwares he/she has completed. So the check boxes in the students Edit vie must be visible. Thats why i cant use @studen.softwares in the edit view, because initially the Student dosent have any Softwares. Commented Nov 9, 2022 at 20:48
  • @max Alos if i use f.fields_for :software (not f.fields_for :softwares) the checkboxes will appear but i get unpermitted params in the controller Commented Nov 9, 2022 at 20:55
  • And the admin must be able to create new Softwares and Courses. Commented Nov 9, 2022 at 21:04

1 Answer 1

0

You don't need accepts_nested_attributes_for just to select existing records and associate them with something. Its only needed if you need to create/update the other record (the course or software) at the same time.

I'm also guessing you don't actually want to have a one-to-many assocation and duplicate every course and every software for each user - instead you want a many to many assocation and some data normalization.

So create a join table to hold the assocation between users and courses for example:

class User < ApplicationRecord
  has_many :enrollments, foreign_key: :student_id
  has_many :courses, through: :enrollments
end

# rails g model enrollment student:belongs_to course:belongs_to
class Enrollment < ApplicationRecord
  belongs_to :student, class_name: 'User'
  belongs_to :course
end

class Course < ApplicationRecord
  has_many :enrollments
  has_many :students, through: :enrollments
end

And then you just create inputs that use the course_ids / course_ids= setter and getter created by has_many :courses, through: :enrollments.

<%= form_with(model: @student, url: auth_student_path(@student), method: :put) do |f| %> 
  <div class="field">
    <%= f.label :course_ids, 'Select your courses' %>
    <%= f.collection_select :course_ids, @courses, :id, :name, multiple: true %>
  </div>

  # ...
<% end %>

And then you just whitelist an array of ids in your controller:

params.require(:user)
      .permit(
        # ...
        course_ids: []
      )

In fact if your ever passing existing records as anything but an ID you're doing it very wrong.

There are still plenty of issues with this code but this should at least be nudge in the correct direction.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.