Rails HABTM relationship not working with polymorphic relationship
Question
I have two models: Student and Project. A student HABTM projects and a Project HABTM students. Here are the two models:
class Student < User
has_many :relationships, dependent: :destroy
has_many :employers, through: :relationships
has_and_belongs_to_many :projects, join_table: :projects_students
end
class Project < ActiveRecord::Base
has_many :relationships
belongs_to :employer
has_and_belongs_to_many :students, join_table: :projects_students
end
As you can see, Student uses polymorphic inheritance from User (The user table has a type column, one of the values is Student). Here is the controller that creates projects:
def create
@project = current_user.projects.new(project_params)
respond_to do |format|
if @project.save
format.html { redirect_to @project, notice: 'Project was successfully created.' }
format.json { render action: 'show', status: :created, location: @project }
else
format.html { render action: 'new' }
format.json { render json: @project.errors, status: :unprocessable_entity }
end
end
end
def project_params
params.require(:project).permit(:title, :category, :location, :budget,
:description, :projectdoc)
end
Project and Student are connected through the join_table :projects_students:
create_table "projects_students", force: true do |t|
t.integer "student_id"
t.integer "project_id"
end
add_index "projects_students", ["project_id"], name: "index_projects_students_on_project_id", using: :btree
add_index "projects_students", ["student_id"], name: "index_projects_students_on_student_id", using: :btree
The problem is that when a project is created, the student_id is not being passed to the projects_students table. How can I fix this?
Solution
I think you mean to say that Student uses "single table inheritance" rather than "polymorphic inheritance" of which there is no such thing.
That said, since the HABTM association is on users and not students, I'd check in the console to see if this works:
Student.first.projects << Project.first
Next thing I'd do is to use "build" instead of "new" when instantiating the project:
@project = current_user.projects.build project_params
I suppose this is only for creating new projects, and that there is a different route for adding students to projects.
OTHER TIPS
I think you're thinking about this wrong. Generally the _id
is reserved for foreign keys to a related table. Since there is no Student
table, rails may be unable to link the student_id
in your join table appropriately.
Try changing your join table:
create_table "projects_users", force: true do |t|
t.integer "user_id"
t.integer "project_id"
end
add_index "projects_users", ["project_id"], name: "index_projects_users_on_project_id", using: :btree
add_index "projects_users", ["user_id"], name: "index_projects_users_on_user_id", using: :btree
Your join table shouldn't care about your STI setup. You can handle that in your models.
So then just cleanup the associations:
class Student < User
has_many :relationships, dependent: :destroy
has_many :employers, through: :relationships
has_and_belongs_to_many :projects, join_table: :projects_users, foreign_key: :user_id
end
class Project < ActiveRecord::Base
has_many :relationships
belongs_to :employer
has_and_belongs_to_many :students, join_table: :projects_users, class_name: 'Student', association_foreign_key: :user_id
end