2009-10-16 7 views
16

J'utilise l'héritage de table unique pour gérer différents types de projets.STI et formulaire_pour problème

Modèles:

class Project < ActiveRecord::Base 
end 

class SiteDesign < Project 
end 

class TechDesign < Project 
end 

action Edit de projects_controller:

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

Voir edit.html.erb:

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

action Mise à jour de 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 

Puis-je faire quelques modifications d'entrée TechDesign sur la vue de modifier et d'obtenir l'erreur:

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

En parametrs il est évident que, au lieu du nom du paramètre de projet que je tech_design Paramètres:

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

Comment réparer?

Répondre

27

Voici la source de votre problème. Ceci définit @project comme une instance d'un objet TechDesign.

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

Vous pouvez vous assurer que les choses fonctionnent comme vous le souhaitez en spécifiant: projet pour un nom dans l'appel form_for.

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

Merci pour votre réponse. Après ces chages j'ai cette erreur: Aucune action n'a répondu à 1. Actions: créer, détruire, éditer, indexer, nouveau, montrer, et mettre à jour – ebsbk

+1

Après avoir ajouté ce map.connect "projects /: id/edit", : controller => "projects",: action => "edit" à l'erreur routes.rb disparue. La question est pourquoi ça ne marche pas sans map.resources: les projets sont déjà présents dans les routes? – ebsbk

+11

Dans Rails 3.1, écrivez l'instruction form_for en tant que <% = form_for @project,: as =>: projet do | f | %> – Cygwin98

2

Une note aléatoire: Si vous utilisez l'héritage de table unique (STI) et oubliez de retirer la méthode initialize de définitions de sous-classe, vous obtiendrez un même « objet nul quand on ne s'y attendait pas » exception.

Par exemple:

class Parent < ActiveRecord::Base 
end 

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

Dans mon cas, j'ai utilisé mon IDE pour créer les classes d'enfants et l'IDE a créé la méthode d'initialisation. Ça m'a pris une éternité pour traquer ...

6

Pour Rails 3

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

Pour Rails 4, je lui ai confirmé la seule chose qui a semblé fonctionner pour moi est de spécifier explicitement l'URL et la Paramètres AS:

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

Cela me semble moche!