Как получить связанные с HABTM объекты в форме после сбоя проверки? - PullRequest
2 голосов
/ 04 августа 2011

У меня очень распространенные отношения HABTM между продуктом и категорией.Я основан на Railscasts Episode # 17 .Проблема, с которой я сталкиваюсь, связана с тем, как все категории выбираются, чтобы показать их в форме продукта (так считает Бейтс):

<% for category in Category.find(:all) %>
  <div>
    <%= check_box_tag "product[category_ids][]", category.id, @product.categories.include?(category) %>
    <%= category.name %>
  </div>
<% end %>

, но я хочучтобы реализовать это следующим образом:

<% for category in @categories %>

, где в контроллере определено @categories:

def edit
  @categories = Categories.all
  @product = Product.find params[:id]
end

Все идет гладко, пока не произойдет сбой проверки.Скажем, какое-то поле не может быть пустым, и поэтому перенаправление (при действии обновления ProductsController) возвращает меня к edit:

def update
    @product = Product.find(params[:id])
    @supplier.category_ids = params[:product][:industry_category_ids] ||= []

  respond_to do |format|
    if @product.update_attributes(params[:product])
      format.html { redirect_to @supplier, notice: 'Profile was successfully updated.' }
      format.json { head :ok }
    else
      format.html { render action: "edit" } <=== HERE
     format.json { render json: @supplier.errors, status: :unprocessable_entity }
    end
  end
end

. В этот момент я получаю следующую ошибку:что @categories в соответствующей форме равно nil:

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each

...
<% for ic in @industry_categories %> <==== HERE
...

Итак, есть ли способ сохранить лучшие практики MVC для достижения этой цели?Или я просто должен сделать это так, как Бейт?

Другими словами, возможно иметь form_for скажем @product с флажками для объектов, связанных с HABTM, и быть перенаправленным на него после сбоя проверки, НО без извлечения материала из представления (Category.all) (т.е. делать это на соответствующем контроллере @categories = Category.all, как я показал ранее)

Спасибо!

1 Ответ

2 голосов
/ 04 августа 2011

Заполните @categories, когда вы не пройдете проверку:

def update
    @product = Product.find(params[:id])
    @supplier.category_ids = params[:product][:industry_category_ids] ||= []

  respond_to do |format|
    if @product.update_attributes(params[:product])
      format.html { redirect_to @supplier, notice: 'Profile was successfully updated.' }
      format.json { head :ok }
    else
     @categories = Categories.all <--- HERE
     format.html { render action: "edit" }
     format.json { render json: @supplier.errors, status: :unprocessable_entity }
    end
  end
end

Когда вы вызываете "render: action", Rails просто продолжает обработку текущего запроса и отображает отображение представления вуказано.Таким образом, в этом случае вы повторно визуализируете представление «edit» (потому что вы провалили проверку), но поскольку в действии «update» не объявлено никакой переменной @categories, вы получите исключение nil reference.

...