ruby на рельсах, не может передать значения check_box_tag обратно в update_attributes

У меня есть довольно простое приложение на Rails, которое выполняет математические тесты. Пользователи могут создавать математические задачи с вопросом и ответом. Они также могут создавать экзамены с названием. Модели связаны с отношением has_many_and_belongs_to, потому что у каждого теста может быть много проблем, и каждая проблема может принадлежать множеству тестов. Эта связь, кажется, работает хорошо в том, что когда я удаляю проблемы или экзамены, списки связанных объектов обновляются. В настоящее время у меня есть то, что, когда вы создаете экзамен, представление дает вам список флажков, по одному для каждой проблемы в базе данных проблем. Пользователь нажимает флажки для задач, которые они хотят в своем экзамене, и какие бы флажки не были установлены, эти проблемы добавляются к экзамену. Я покажу код для обновления, так как это представление, которое я использовал для тестирования.

Вот мнение:

  <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 %>

Я должен был использовать check_box_tag потому что если бы я попытался использовать builder.check_box, это не сохранит, какие ящики уже были отмечены.

Мой контроллер:

  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

В представлении я сохранил все результаты флажков в массиве problem_ids. Я знаю, что этот массив заполняется правильно, потому что, когда я добавляю следующий код, он работает.

@exam.problems = []
params[:exam][:problem_ids].each {
  |prob_id|
  @exam.problems << Problem.find(prob_id)
}

Очевидно, это очень хакерский способ сделать это, так как я каждый раз вручную строю список проблем, но я просто не могу понять, как получить результаты этих флажков для автоматического заполнения в update_attributes метод. Есть идеи?

ОБНОВЛЕНИЕ: В соответствии с предложением Донована ниже, я применил следующий метод в моей модели экзамена:

  def problem_ids=(some_problem_ids)
    @exam.problems.clear
    some_problem_ids.each {
      |prob_id|
      @exam.problems << Problem.find(prob_id)
    }
  end

Насколько я понимаю, это должен быть метод "сеттера" для problem_ids, К сожалению, список проблем все еще не обновляется, когда я использую следующую строку в моем контроллере экзамена:

@exam.update_attributes(params[:exam].permit(:title, :problem_ids))

PS я должен поставить .permit(:title, :problem_ids) немного или я получу ForbiddenAttributesError,

2 ответа

Решение

Спасибо за вашу помощь, но я наконец-то понял это самостоятельно. Проблема заключалась в том, что, хотя я позволял problem_ids чтобы передать в качестве параметра, я не говорил контроллеру, что это на самом деле массив. Итак, как только я изменил соответствующую строку на:

@exam.update_attributes(params[:exam].permit(:title, problem_ids: []))

это сработало отлично!

@exam.problems - это список объектов, но также должен быть problem_ids Метод сеттера на экзамене из-за отношений, поэтому

@exam.update_attributes(params[:exam])

должен делать то, что вы хотите. Если по какой-то причине вам нужно только обновить problem_ids, это должно сработать:

@exam.update_attribute(:problem_ids, params[:exam][:problem_ids])

Примечание: я пропустил rails4 strong_parameters, чтобы сделать ответ универсальным для rails 3 или 4, убедитесь, что вы используете подходящие методы для вашей версии.

Другие вопросы по тегам