2009-10-16 3 views
16

Sto utilizzando l'ereditarietà di tabelle singole per la gestione di diversi tipi di progetti.STI e form_for problem

Modelli:

class Project < ActiveRecord::Base 
end 

class SiteDesign < Project 
end 

class TechDesign < Project 
end 

Modifica azione da projects_controller:

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

Vista edit.html.erb:

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

Aggiornamento azione del 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 

poi faccio alcune modifiche di ingresso TechDesign su modificare vista e ottenere errore:

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.[] 

In parametrs è ovvio che al posto del progetto nome del parametro ho tech_design Parametri:

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

Come per risolverlo?

risposta

27

Ecco la fonte del problema. Questa è l'impostazione di @project come istanza di un oggetto TechDesign.

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

È possibile garantire le cose funzionano nel modo desiderato specificando: progetto per un nome nella chiamata form_for.

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

Grazie per la risposta. Dopo queste chage ho ricevuto questo errore: Nessuna azione ha risposto a 1. Azioni: crea, distruggi, modifica, indicizza, visualizza, visualizza e aggiorna – ebsbk

+1

Dopo aver aggiunto questo map.connect "projects /: id/edit", : controller => "projects",: action => "edit" to routes.rb error disapeared. La domanda è: perché non funziona senza di essa se map.resources: i progetti già presenti nelle rotte? – ebsbk

+11

In Rails 3.1, scrivi l'istruzione form_for come <% = form_for @project,: as =>: project do | f | %> – Cygwin98

2

Una nota a caso: se si utilizza l'ereditarietà singola tabella (STI) e dimentica di rimuovere il inizializzare metodo dal le definizioni di sottoclasse si otterrà un simile "oggetto nil quando non hai lo aspetti" eccezione.

Ad esempio:

class Parent < ActiveRecord::Base 
end 

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

Nel mio caso, ho usato la mia IDE per creare le classi figlie e l'IDE ha creato il metodo di inizializzazione. Mi ha portato sempre di rintracciare ...

6

Per Rails 3

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

Per Rails 4, mi hanno confermato l'unica cosa che è sembrato di lavorare per me è quello di specificare esplicitamente l'URL e il Parametri AS:

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

Sembra brutto per me!