1
votes

I have the following models:

class RandomExam < ActiveRecord::Base
  has_many :random_exam_sections
  has_many :sections, :through => :random_exam_sections
end

class Section < ActiveRecord::Base
  has_many :random_exam_sections
  has_many :random_exams, :through => :random_exam_sections

class RandomExamSection < ActiveRecord::Base
  belongs_to :random_exam
  belongs_to :section
end

The idea is to have certain configurations to create random exams, so this tables help to select which sections do you need and then also select the number of questions per section, here are the attributes of each table:

RandomExam: name(string), created_at(datetime), updated_at(datetime)

Section: name(string), created_at(datetime), updated_at(datetime)

RandomExamSection: random_exam_id(integer), section_id(integer), questions_number(integer)

As you can see the number of questions per section attribute is inside the RandomExamSections table and I want to access it in a form that is displayed from the RandomExam controller, here is my form:

<%= form_for (@random_exam) do |f|  %>
    <div class="row">

        <div class="input-field col s12">
            <%= f.label :name, 'Name' %>
            <%= f.text_field :name, placeholder: 'Enter the name of the       configuration' %>
        </div>

    </div>

    <% @sections.each do |section| %>

        <div class="row <%= dom_id(section) %>">
            <div class="col s4">
                <%= check_box_tag 'random_exam[section_ids][]',  section.id,
                @random_exam.section_ids.include?(section.id), id:     dom_id(section), class: "section-checkbox #{dom_id(section)}" %>
                <%= label_tag dom_id(section), (raw sanitize     section.name, tags: %w(h2 p strong em a br b i small u ul ol li     blockquote), attributes: %w(id class href)),
                class: "name #{dom_id(section)}" %>
            </div class="col s4">
            <div>
                <%= text_field_tag "random_exam[random_questions_numbers][#{section.id}][]", nil,
                                   :placeholder => 'Enter the number of questions' %>
            </div>

        </div>
    <% end %>

    <div class="form-group">
        <%= f.submit class: "btn waves-effect waves-light green"  %>
    </div>

<% end %>

My controller:

def create
  @random_exam = RandomExam.new(random_exam_params)
  if @random_exam.save
  assign_random_questions_number
  flash[:success] = 'Random configuration created successfully'
  redirect_to @random_exam
else
  flash.now[:danger] = @random_exam.errors.full_messages.to_sentence
  render 'new'
end

def assign_random_questions_number
  if params[:random_exam][:'random_questions_numbers'] == nil
    return
  end


params[:random_exam][:'section_ids'].each do |key, value|
  record = RandomExamSection.search_ids(@random_exam.id, key)

  record.each do |random_exam_section_record|
    number_of_questions = params[:random_exam][:'random_questions_numbers'][key].first.to_i
    random_exam_section_record.update(questions_number: number_of_questions)
  end
end

end

I'm getting a TypeError: TypeError: nil is not a symbol nor a string when I update the record in the method assign_random_questions_number

This error even appears when I run this on the console

random = RandomExamSection.first
random.update(questions_number: 10)

Or when I run:

random = RandomExamSection.first
random.questions_number = 10
random.save

EDIT

I ended up deleting the association in RandomExamSection and recreating it inside 'assign_random_questions_number' with the questions_number

Thanks.

1
hi and welcome to stack overflow. So - I notice that there isn't any form-field for that number of sections at all. What have you tried to put in your form to make that work and what, if any, errors did you see when you tried that? - Taryn East
@TarynEast Well, I have tried several stack overflow answers, the problem is that they use nested fields, not something we are using in our implementation. In fact, we have no idea what the field should be named because when we save it, it does not appear. - Dazt
so... show us what you tried (edit your question and put it there), and we can help you fix it so that it does appear :) AFAICT it's just another field... so add another field named what you want. - Taryn East
Also - have you heard of fields_for ? apidock.com/rails/ActionView/Helpers/FormHelper/fields_for It might be better to use that for your sections... - Taryn East
@TarynEast I have updated the answer, now I'm getting a TypeError when I try to update the join table record, even when I do it from the console. Do you know why this is happening? - Dazt

1 Answers

1
votes

If you use nested_attributes you can do something like this:

#form
<h4>Selected exams</h4>
<%= f.fields_for :random_exam_sections do |b| %>
  <%= b.hidden_field :section_id %>
  <%= b.label :selected, b.object.section.name %>
  <%= b.check_box :selected, { checked: !b.object.id.blank? } %>
  <br>
  <%= b.label :question_numbers %>
  <%= b.text_field :questions_number %>
 <% end %>

#RandomExamModel
class RandomExam < ApplicationRecord
  has_many :random_exam_sections, inverse_of: :random_exam
  has_many :sections, :through => :random_exam_sections

  accepts_nested_attributes_for :random_exam_sections, reject_if: :is_not_selected


  private
  def is_not_selected(attr)
    attr["selected"] == '0'
  end
end

# RandomExam
class RandomExamSection < ApplicationRecord
  belongs_to :random_exam
  belongs_to :section

  attr_accessor :selected
end

# Controller
# GET /random_exams/new
  def new
    @random_exam = RandomExam.new
    @random_exam.random_exam_sections.build(Section.all.map{|s| {section_id: s.id}})
  end

The idea basically is

- Build on controller the random_exam_sections to be selected
- Write a form that allows to you 'select' one option and assign the number
- Then, validate if the random_exam_section of a sections was selected (this why i made that `attr_accessor :selected`, i need a place to write if user select the exam_section)
- If was selected, save.

The trick here is build on the controller, then select on the view and validate the selected on the model. Here i made an example if you need help: https://github.com/afromankenobi/nested_attr_demo

To add sections when the random_exam_sections is already created you should probably use javascript. Maybe this railscasts can help you http://railscasts.com/episodes/196-nested-model-form-part-1