Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6250899
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 24, 20262026-05-24T13:30:49+00:00 2026-05-24T13:30:49+00:00

I deeply searched the web in order to find a clean and simple way

  • 0

I deeply searched the web in order to find a clean and simple way to deal with attributes initialization on the join model of a has_many :through relation, but I did not find a best solution for my need.

In the exaple I provide below, I need to automatically set the attribute role of the Training join model when I create or update a Course object.

This is my model:

QUALIFICATIONS = ["Theoretical Instructor", "Practical Instructor"]

class Course < ActiveRecord::Base
  has_many :trainings, dependent: :destroy

  has_many :theoretical_instructors, through: :trainings, source: :trainer, conditions: { "trainings.role" => "Theoretical Instructor" }
  accepts_nested_attributes_for :theoretical_instructors

  has_many :practical_instructors, through: :trainings, source: :trainer, conditions: { "trainings.role" => "Practical Instructor" }
  accepts_nested_attributes_for :practical_instructors
end

class Trainer < ActiveRecord::Base
  has_many :trainings, dependent: :destroy
  has_many :courses, through: :trainings
end

class Training < ActiveRecord::Base
  belongs_to :trainer
  belongs_to :course

  # Join model has the :role attribute, that I wish I could validate this way:  
  # validates :role, presence: true, inclusion: { in: QUALIFICATIONS }
end

The rationale behind this model is that I want to save Training objects in a single table. I don’t want to create the TheoreticalInstructor and the PracticalInstructor join models (potentially exploding the number of tables) to solve this problem.

This view provides the form to submit a new Course:

<%= form_for @course do |course_form| %>
  <%- # fields for course attributes, as usual... %>

  <%= course_form.label :theoretical_instructor_ids %><br />
  <%= course_form.select :theoretical_instructor_ids, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, {  }, { multiple: true } %>

  <%= course_form.label :practical_instructor_ids %><br />
  <%= course_form.select :practical_instructor_ids, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, {  }, { multiple: true } %>

  <%= course_form.submit %>
<% end%>

The question is: what can I do in order to make @course = Course.new(params[:course]) the only line of code in the Course controller needed to save this association on submit of the previous form?

Differently from this question I don’t want to create new Trainer objects when I create a new Course: I want to choose them from those already present in the DB (through a multiselect input field).

What I need is that something like @course.theoretical_instructor_ids = [1, 2] creates two Training objects with the role attribute set to Theoretical Instructor

I’m thinking on an after_initialize callback on Training that set role basing on the relation name (:theoretical_instructors and :practical_instructors), but I really don’t know how to do it. Any advice? Am I missing some point?

Thank you guys!

EDIT 1 from oli-g

This question deals with a similar problem: the difference is that I don’t want to build Trainer objects when I create a new Course, but I simply want to associate existing Trainer objects to a new Course.

EDIT 2 from oli-g

Basing on this (a 5 years old post) and this blog posts, I’ve changed the Course model in this way:

class Course < ActiveRecord::Base
  has_many :trainings, dependent: :destroy

  has_many :theoretical_instructors, through: :trainings, source: :trainer, conditions: ["trainings.role = ?", "Theoretical Instructor"] do
    def <<(theoretical_instructor)
      Training.send(:with_scope, create: { role: "Theoretical Instructor" }) { self.concat theoretical_instructor }
    end
  end
  accepts_nested_attributes_for :theoretical_instructors

  has_many :practical_instructors, through: :trainings, source: :trainer, conditions: ["trainings.role = ?", "Practical Instructor"] do
    def <<(practical_instructor)
      Training.send(:with_scope, create: { role: "Practical Instructor" }) { self.concat practical_instructor }
    end
  end
  accepts_nested_attributes_for :practical_instructors
end

This code enables me to do a thing like this

:001 > c = Course.first
=> #<Course id: 1>
:002 > t1 = Trainer.first
=> #<Trainer id: 1, name: "Tom">
:003 > c.theoretical_instructors << t1
=> #<Trainer id: 1, name: "Tom">
:004 > Training.all
=> [#<Training id: 1, role: "Theoretical Instructor", trainer_id: 1, course_id: 1>]

This is an acceptable workaround, even if in my controller I still can’t do just @course = Course.new(params[:course]), but I have to create Training objects iterating on params[:course][:theoretical_instructor_ids] and params[:course][:practical_instructor_ids].

But I am curious, so the question remains open: what can I do in order to enable @course = Course.new(params[:course]) to build Training objects along with the Course?

Now… I think I discovered a bug in Rails:

:005 > c.practical_instructors
=> []        # correct
:006 > c.practical_instructor_ids
=> []        # obviously
:007 > c.reload
=> #<Course id: 1>
:008 > c.practical_instructor_ids
=> [1]       # WRONG!!!
:009 > c.practical_instructors
=> []        # now it's correct...
:010 > c.practical_instructor_ids
=> []        # WTF!?

I think I will report this at github issues…

EDIT 3 by oli-g

Bug reported at github

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-24T13:30:50+00:00Added an answer on May 24, 2026 at 1:30 pm

    Your issue is that you won’t be able to add associations until after your record has been created. In this case, the Training associations are stored using the Course record id, and the Course id isn’t defined until after the Course is saved for the first time. What you’ll want to do is to use the after_create callback to call a function after the record has been created.

    Add this to the end of your Course model:

    # Use attr accessors to store the initial values so they won't conflict with the *_instructor_ids methods defined above 
    attr_accessor :create_theoretical_instructors
    attr_accessor :create_practical_instructors
    # This will call the create_training_records function after the record is created
    after_create :create_training_records
    
    private
    def create_training_records
      create_theoretical_instructors.each do |instructor_id|
        self.theoretical_instructors << Instructor.find(instructor_id)
      end
      create_practical_instructors.each do |instructor_id|
        self.practical_instructors << Instructor.find(instructor_id)
      end
      save!
    end
    

    And change the form in your view to use the new attr_accessors:

    <%= course_form.label :create_theoretical_instructors %><br />
    <%= course_form.select :create_theoretical_instructors, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, {  }, { multiple: true } %>
    
    <%= course_form.label :create_practical_instructors %><br />
    <%= course_form.select :create_practical_instructors, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, {  }, { multiple: true } %>
    

    Now when you submit the form, it will write the instructor ids to the new Course instance variables; after the Course has been validated and saved, it will automatically create the new associations.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am trying to find especially large files on a file share with deeply
I'm having a difficult time to find an opening div in deeply nested HTML
I'm trying to find a way to terminate a loop when the user hits
Is there an easy way to access to the root view from a deeply
If I have a deeply-nested model graph, coming from the server (a lot of
I have a custom ActionResult which is more deeply encountering System.Web.HttpException when the remote
I'm using Perl's XML::Simple to parse deeply nested XML and would like to extract
I've been exploring javascript more deeply lately, playing around with a node,redis,socket.io,express simple webapp.
I have a deeply nested for-comprehension, simplified to 3 levels below: x, y, and
I am trying to construct a deeply nested associative array but i don't know

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.