Подтвердить что ты не робот

STI и form_for проблемы

Я использую Single Table Inheritance для управления различными типами проектов.

Модели:

class Project < ActiveRecord::Base
end

class SiteDesign < Project
end

class TechDesign < Project
end

Изменить действие из project_controller:

def edit
   @project = Project.find(params[:id])
end

Просмотреть edit.html.erb:

<% form_for(@project, :url => {:controller => "projects",:action => "update"}) do |f| %>
    ...
    <%= submit_tag 'Update' %>
<% end %>

Обновить действие project_controller:

def update
    @project = Project.find(params[:id])
    respond_to do |format|
      if @project.update_attributes(params[:project])
        @project.type = params[:project][:type]
        @project.save
        flash[:notice] = 'Project was successfully updated.'
        format.html { redirect_to(@project) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @project.errors, :status => :unprocessable_entity }
      end
    end
  end

Затем я делаю некоторые изменения в записи TechDesign в режиме редактирования и получаю ошибку:

NoMethodError in ProjectsController#update

You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]

В параметрах очевидно, что вместо имени параметра проекта у меня есть tech_design Параметры:

{"commit"=>"Update",
 "_method"=>"put",
 "authenticity_token"=>"pd9Mf7VBw+dv9MGWphe6BYwGDRJHEJ1x0RrG9hzirs8=",
 "id"=>"15",
 "tech_design"=>{"name"=>"ech",
 "concept"=>"efds",
 "type"=>"TechDesign",
 "client_id"=>"41",
 "description"=>"tech"}}

Как это исправить?

4b9b3361

Ответ 1

Вот источник вашей проблемы. Это устанавливает @project как экземпляр объекта TechDesign.

def edit
   @project = Project.find(params[:id])
end

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

<% form_for(:project, @project, :url => {:controller => "projects",:action => "update"}) do |f| %>
    ...
    <%= submit_tag 'Update' %>
<% end %>

Ответ 2

Для Rails 3

<% form_for(@project, :as => :project, :url => {:controller => "projects",:action => "update"}) do |f| %>
...
   <%= submit_tag 'Update' %>
<% end %>

Ответ 3

Случайное примечание. Если вы используете однонаправленное наследование таблицы (STI) и забыли удалить метод инициализации из своих определений подкласса, вы получите аналогичное исключение "нулевой объект, когда вы этого не ожидали".

Например:

class Parent < ActiveRecord::Base
end

class Child < Parent
  def initialize
    # you MUST call *super* here or get rid of the initialize block
  end
end

В моем случае я использовал свою IDE для создания дочерних классов, а среда IDE создала метод инициализации. Принял меня навсегда, чтобы отследить...

Ответ 4

Для Rails 4 я подтвердил, что единственное, что, казалось, работает для меня, - это явно указать URL-адрес и параметры AS:

<% form_for(@project, as: :project, url: {controller: :projects, action: :update}) do |f| %>
    ...
<% end %>

Кажется уродливым для меня!