1

Is there a way to update a field relative to a many-to-many associations via form_for?

Theses are my models:

  class Grad < ActiveRecord::Base
    belongs_to :school
    has_many :grad_courses
    has_many :courses, through: :grad_courses
    accepts_nested_attributes_for :grad_courses, :courses
  end

  class Course < ActiveRecord::Base
    belongs_to :school
    has_many :grad_courses
    has_many :grads, through: :grad_courses
  end

  class GradCourse < ActiveRecord::Base
    belongs_to :grad
    belongs_to :course
  end

Here is the many-to-many migration with the extra property (semester):

  create_table "grad_courses", force: :cascade do |t|
    t.integer  "grad_id"
    t.integer  "course_id"
    t.integer  "semester"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

What i'm trying to do is add and update the relations with the semester information dynamically with a form collection set (using form_for and chosen).

<%= form_for @grad, html: {class: "form-horizontal"} do |f| %>
    ...    
       <% (1..@grad.max).each do |semester| %>
            <div class="form-group">
                <%= f.label :course_ids, "#{semester}º semestre", class: "col-sm-2 control-label"  %>
                <div class="col-sm-10">
                  <%= f.collection_select :course_ids, @courses, :id, :name, {include_blank: true}, {multiple: true, :class=>'chosen-select form-control'} %>
                </div>
            </div>
        <% end %>  
...   
    <% end %>

This way, it is creating and updating the grad_courses, but without the semester.

I've tried lot of things, but didn't had success.

I'm able to manage the semester's info directly, like in this post: http://stackoverflow.com/questions/2168442/many-to-many-relationship-with-the-same-model-in-rails#=

I could pass an array with a hidden field, and manage the form manually, but it would take too much work, so I was wondering if there is an easy way to do this.

Something like :grad_course[:course_id][:semester] in :grad params? Is it possible?

the grad_course_controller:

      def update
        respond_to do |format|
          if @grad.update(grad_params)
            format.html { redirect_to @grad, notice: 'Cursos adicionados com sucesso' }
          else
            format.html { render :edit }
          end
        end
      end

      private
        def set_grad
          @grad = Grad.find(params[:id])
        end

        def set_courses
           @courses = Course.where(school_id: @grad.school_id) 
           @gc = GradCourse.where(grad_id: @grad.id)
        end
list through.
        def grad_params
          params.require(:grad).permit(:name, :min, :max, :school_id, course_ids: [] )
        end

Update

I've been trying to solve this using Peter's advices, so I tried nested_attributes and fields_for. But I'm having problems with it too.

I need one collection_sellect for each semester (from 1 to Grad.max number), where the options will be the courses available for that semester (@courses), and for the selected ones a grad_course relation needs to be created or updated.

The problem with field_for is that one field is generated for every grad_course relation, and since each field is related with the grad_course.id I`m not able to add new ones properly.

Here is one of the tries i've made with fields for:

  <%= f.fields_for :grad_courses do |builder| %>
  <p>
    <%= builder.text_field :semester %><br />
    <%= builder.collection_select :course_id, @courses, :id, :name, {include_blank: true}, {multiple: true, :class=>'chosen-select form-control'} %>

  </p>
  <% end %>

with these changes in the grad_controller:

def grad_params
  params.require(:grad).permit(:name, :min, :max, :school_id, course_ids: [], grad_courses_attributes: [:id, :course_id, :grad_id, :semester ])
end
Cœur
  • 37,241
  • 25
  • 195
  • 267
mknarciso
  • 15
  • 6
  • Why you don't use `fields_for` . that will be easier to do that. http://railscasts.com/episodes/196-nested-model-form-part-1 . You want to create `@grad.max` of grad_course. In controller just build it first then in view everything setting for you – Peter89 Jan 29 '16 at 03:13
  • _"I could pass an array with a hidden field, and manage the form manually, but it would take too much work, so I was wondering if there is an easy way to do"_ Look at the size of your question! Rails... =/ – Gustavo Schmidt Jan 29 '16 at 19:18

1 Answers1

0

Have you tried to add the :course_ids on the permit list?

Like this:

def grad_params
  params.require(:grad).permit(:name, :min, :max, :school_id, :course_ids)
end
Samuel G. P.
  • 3,004
  • 2
  • 29
  • 36
  • Yes, actually it was a typo, it was working with :course_ids[] there. Now I'm trying with nested attributes, like Peter suggested above, and it's like these: def grad_params params.require(:grad).permit(:name, :min, :max, :school_id, grad_courses_attributes: [ :id, :course_id, :grad_id, :semester ]) end – mknarciso Feb 01 '16 at 12:25
  • can you update the code in the question? it will be easier to debug. – Samuel G. P. Feb 01 '16 at 12:31