STI和form_for问题

我使用单表inheritance来管理不同类型的项目。

楷模:

class Project < ActiveRecord::Base end class SiteDesign < Project end class TechDesign < Project end 

从projects_controller编辑动作:

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

查看edit.html.erb:

  {:controller => "projects",:action => "update"}) do |f| %> ...   

更新projects_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"}} 

怎么解决?

这是您的问题的根源。 这是将@project设置为TechDesign对象的实例。

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

您可以通过指定:form_for调用中的名称项目来确保事情按您所需的方式工作。

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

对于Rails 3

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

随机说明:如果您正在使用单表inheritance(STI)并忘记从子类定义中删除initialize方法,那么当您没有预期时,您将获得类似的“nil对象”exception。

例如:

 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创建了initialize方法。 让我永远追踪......

对于Rails 4,我已经确认对我来说唯一有效的方法是明确指定URL和AS参数:

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

对我来说似乎很难看!