1
votes

I'm working on a project for a class where I have a very large form with Nested Models. Here are the models that are important to the form, as well as their associations:

  • Course: has_many :time_blocks, has_many :tags, through: :taggings, belongs_to :institution, has_many :roles, has_many :users, through: :roles

  • TimeBlock: belongs_to :course

  • Tag: has_many :taggings
  • Tagging: belongs_to :tag, belongs_to :taggable_type
  • Institution: has_many :courses, has_many :users
  • Role: belongs_to :course, belongs_to :user

I am able to create the Nested Form correctly, but I can't get the Nested Models to update correctly. Here is the controller, the form is very long, but I have provided the params for the Nested Models. Note, I cleared out the values from the params, but some of the params have ID values because they exist in the db. I've also included the CoursesHelper to show the helper methods I'm using in the controller.

app/controllers/courses_controller.rb

  def new
    @course = current_user.courses.new

    @course.institution = Institution.new

    4.times { @course.tags.build }
    7.times { @course.time_blocks.build }
  end

  def create
    @course = Course.new(params[:course])

    @course.institution = Institution.new(params[:institution])

    filled_tags = set_tags(params[:tag])
    @course.tags.build(filled_tags)

    filled_time_blocks = set_time_blocks(params[:time_block])
    @course.time_blocks.build(filled_time_blocks)

    if @course.save
      Role.create!(
        user_id: current_user.id, 
        course_id: @course.id, 
        title: 'instructor'
      )

      redirect_to @course
    else
      (4 - filled_tags.count).times { @course.tags.build }
      (7 - filled_time_blocks.count).times { @course.time_blocks.build }

      flash.now[:errors] = @course.errors.full_messages
      render :new
    end
  end

  def edit
  end

  def update
    filled_time_blocks = set_time_blocks(params[:time_block])
    filled_time_blocks.each do |time_block| 
      @course.time_blocks.update_attributes(time_block)
    end 

    filled_tags = set_tags(params[:tag])
    filled_tags.each { |tag| @course.tags.update_attributes(tag) }
    # @course.tags.update_attributes(filled_tags)

    # @course.time_blocks.update_attributes(filled_time_blocks)
    fail
    if @course.update_attributes(params[:course])
      redirect_to @course
    else
      flash.now[:errors] = @course.errors.full_messages
      render :edit
    end
  end

app/helpers/courses_helper.rb

  def set_time_blocks(entries)
    result = []

    days = entries[:day_of_week].reject! { |day| day.blank? }

    days.each do |day|
      time_block = {}

      time_block[:day_of_week] = day
      time_block[:start_time] = entries[day][:start_time]
      time_block[:end_time] = entries[day][:end_time]
      time_block[:id] = entries[day][:id]

      result << time_block
    end

    result
  end

  def set_tags(entries)
    [].tap do |tags|
      entries.each do |entry|
        tags << entry unless entry.values.all?(&:blank?)
      end
    end
  end

  def find_course
    if params.include?(:id)
      @course = Course.find(params[:id])
    else
      flash[:notice] = "Sorry, Could Not Find Course."
      redirect_to current_user
    end
  end

TimeBlock Params

{"sun"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "mon"=>{"start_time"=>"", "end_time"=>"", "id"=>"3"}, "tue"=>{"start_time"=>"", "end_time"=>"", "id"=>"4"}, "wed"=>{"start_time"=>"", "end_time"=>"", "id"=>"5"}, "thu"=>{"start_time"=>"", "end_time"=>"", "id"=>"6"}, "fri"=>{"start_time"=>"", "end_time"=>"", "id"=>"7"}, "sat"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "day_of_week"=>[]}

Tag Params

[{"name"=>"", "id"=>"4"}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}]
1
why don't you want to use accepts_nested_attributes_for ?sevenseacat
This method and question shouldn't be encouraged as this is not how rails is designed. Unless you have a good reason to not use accepts_nested_attributes_for you should not be writing any manual code.KULKING

1 Answers

0
votes

If you cant make it work with accepts_nested_attributes_for then you'll have to write your own setter method(s) manually. Something like:

class Course < ActiveRecord::Base
  def tag_attributes=(tags)
    tags.each do |tag|
      self.tags.build(tag)
    end
  end
end

The method name (tag_attributes= in my example) needs to match the key name that the tag params are listed under