Rails 3.2 Обновление вложенных атрибутов - PullRequest
1 голос
/ 24 января 2012

Вот моя проблема. Если я перейду на Projects#edit, я не смогу изменить курс, которому он назначен. Если я пытаюсь создать для него новый курс или выбрать из существующего, я получаю следующую ошибку:

Couldn't find Course with ID=23 for Project with ID=62
app/controllers/projects_controller.rb:49:in `update'

{...
"project"=>{"title"=>"Sup",
"due_date"=>"2012-01-23",
"course_id"=>"27",                        # THIS IS THE ID OF THE NEW COURSE I WANT
"course_attributes"=>{"name"=>"Calc I",   # THIS IS THE OLD ONE, I don't need this. Why is it passing this?
"number"=>"MATH102",
"user_id"=>"3",
"id"=>"23"},
"description"=>"bla bla bla"},
"commit"=>"Update Project",
"user_id"=>"3",
"id"=>"62"}

Итак, я вижу, что он пытается передать course_attributes, но на самом деле он не устанавливает новый course_id. Я не понимаю, почему передается course_attributes, другая форма пуста, а переданные course_attributes являются атрибутами старого курса. Я хочу установить для course_id значение course_id (27 в данном случае).

ProjectsController

def new
  @project  = @user.projects.new
  @courses = @user.courses    # Used to populate the collection_select
  @project.build_course       # I was informed I need to use this to get the form_for to work
end

def edit
  @project = Project.find(params[:id])
  @courses = @user.courses    # Used to populate the collection_select
end

def update
  @project = Project.find(params[:id])
  @courses = @user.courses

  if @project.update_attributes(params[:project])
    flash[:notice] = 'Project was successfully updated.'
    redirect_to user_projects_path(@user)
  else
    render :edit
  end
end

Строка 49 - это вызов update_attributes.

Другая информация

project.rb

belongs_to :user
belongs_to :course

attr_accessible :course_id, :course_attributes
accepts_nested_attributes_for :course

course.rb

belongs_to :user
has_many :projects

user.rb

has_many :projects
has_many :courses

Таким образом, у проекта есть course_id в базе данных. В настоящее время я создаю или выбираю существующий курс на лету на странице Projects # new. Вот моя форма для этого. Я использую JavaScript-переключатель для переключения между collection_select и двумя text_fields.

Проекты / new.html.haml

= form_for [@user, @project] do |f|
  # This is shown by default
  = f.collection_select :course_id, @courses, :id, :name, { prompt: true }

  .hidden # This is hidden by default and shown using a toggle
    = f.fields_for :course do |builder|
      = builder.text_field :name, class: 'large', placeholder: 'Ex: Calculus I'
      = builder.label :number, 'Number'
      = builder.text_field :number, class: 'new_project_course_number'
      = builder.hidden_field :user_id, value: current_user.id

Теперь, если я нахожусь на странице нового проекта и прикрепляю его к курсу, выбирая существующий курс, он будет работать правильно. Будет создан Project , и course_id будет установлен правильно.

Если я нахожусь на странице нового проекта и создаю курс с помощью переключателя JavaScript, заполняя Имя курса и Номер курса и нажимая Создать, затем это тоже будет работать. Курс будет создан, и Проект будет создан с правильным course_id.

Извините за длинный пост, но я хотел предоставить всю информацию, которую мог. Спасибо!

ОБНОВЛЕНИЕ 1

routes.rb

resources :users do
  resources :projects do
    collection do
      get 'completed'
      match 'course/:course_number' => 'projects#course', as: 'course'
    end
  end

  resources :courses
end

Ответы [ 2 ]

3 голосов
/ 26 января 2012

Предполагая, что ваша форма Projects#edit аналогична вашей Projects#new

Это создает course_attributes в параметрах

  .hidden # This is hidden by default and shown using a toggle
    = f.fields_for :course do |builder|
      = builder.text_field :name, class: 'large', placeholder: 'Ex: Calculus I'
      = builder.label :number, 'Number'
      = builder.text_field :number, class: 'new_project_course_number'
      = builder.hidden_field :user_id, value: current_user.id

Это потому, что если у user есть текущий курс, он будет создавать поля для каждого курса.

Если вы хотите иметь возможность создавать новый курс на лету в edit и new, измените эту строку на:

    = f.fields_for :course, @project.build_course(:user => @user) do |builder|

Это создаст новый course независимо от того, находитесь ли вы в редактировании или новый. (Также вы можете удалить @project.build_course в вашем контроллере таким образом.)

0 голосов
/ 24 января 2012

Вы не перечисляете свои маршруты, но при условии, что они настроены правильно, тогда обновление ProjectsController должно быть в состоянии сделать что-то вроде:

@course = Course.find(params[:course_id])
...