I have a fairly simple Rails application that does things with math quizzes. Users can create math problems with a question and an answer. They can also create exams with a title. The models are linked with has_many_and_belongs_to relationship because each quiz can have many problems, and each problem can belong to many quizzes. That relationship seems to be working well in that when I delete problems or exams, the related object lists are updated. The way I have it currently is that, when you're creating an exam, the view gives you a list of check boxes, one for each problem in the problem database. The user clicks the check boxes for the problems they want in their exam, and whichever boxes are checked, those problems are added to the exam. I'll show the code for the update, since that's the view I've been using to test with.
Here's the view:
<h2>Available Problems:</h2>
<% Problem.all.each do |prob| %>
<%= f.fields_for "exam[problem_ids][]", prob do |builder| %>
<p>
<%= check_box_tag "exam[problem_ids][]", prob.id, @exam.problems.include?(prob) %>
<%= prob.question %> = <%= prob.answer %> | <%= link_to "Edit", edit_problem_path(prob) %>
</p>
<% end %>
<% end %>
I had to use check_box_tag
because if I tried to use builder.check_box
, it wouldn't save which boxes were already checked.
My controller:
def update
@exam = Exam.find(params[:id])
if @exam.update_attributes(params[:exam].permit(:title, :problem_ids))
redirect_to @exam
else
render 'edit'
end
end
In the view, I saved all the checkbox results in the problem_ids array. I know this array is being filled correctly, because when I add the following code, it works.
@exam.problems = []
params[:exam][:problem_ids].each {
|prob_id|
@exam.problems << Problem.find(prob_id)
}
Obviously, this is a very hackey way to do it, since I manually build the problem list each time, but I just can't for the life of me figure out how to get those checkbox results to automatically populate in the update_attributes
method. Any ideas?
UPDATE: In accordance to Donovan's suggestion below, I implemented the following method in my exam model:
def problem_ids=(some_problem_ids)
@exam.problems.clear
some_problem_ids.each {
|prob_id|
@exam.problems << Problem.find(prob_id)
}
end
As I understand it, this is supposed to be a "setter" method for problem_ids
. Sadly, the problem list is still not updated when I use the following line in my exam controller:
@exam.update_attributes(params[:exam].permit(:title, :problem_ids))
P.S. I have to put the .permit(:title, :problem_ids)
bit or else I'll get a ForbiddenAttributesError
.
Thank you for all your help, but I finally figured it out on my own. The problem was that, even though I was allowing
problem_ids
to be passed as a parameter, I wasn't telling the controller that it was actually an array. So, once I changed the relevant line to:it worked perfectly!