2009-12-14 8 views
1

J'ai quelques modèles (site et serveur) qui sont liés les uns aux autres via has_many: through. ils appartiennent aussi tous les deux à: user. dans mes sites/nouvelle vue, je crée un nouveau site, et je crée un nouveau serveur en utilisant un formulaire imbriqué. fields_for: servers. Tout fonctionne comme prévu, sauf que le serveur qui finit par être créé n'a pas de nom d'utilisateur rempli. Comment est-ce que je m'assure que c'est?Rails clé étrangère est nulle sous forme imbriquée

Mes sites_controller nouvelles et créer des méthodes:

def new 
    @user = current_user 
    @site = @user.sites.build 
    @servers = @user.servers.all 

    # let there be one server linked 
    @site.site_servers.build 

    # @user.servers.build if @user.servers.empty? 
    @site.servers.build(:user_id => current_user.id) if @site.servers.empty? 

    respond_to do |format| 
     format.html # new.html.erb 
     format.xml { render :xml => @site } 
    end 
    end 

    def create 
    @site = current_user.sites.build(params[:site]) 

    respond_to do |format| 
     if @site.save 
     flash[:notice] = 'Site was successfully created.' 
     format.html { redirect_to(@site) } 
     format.xml { render :xml => @site, :status => :created, :location => @site } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @site.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

Si vous remarquez les lignes de commentaires, ce sont des choses que j'essayées qui ne fonctionnait pas.

Modèles:

class User < ActiveRecord::Base 
    acts_as_authentic 

    has_many :sites 
    has_many :servers 
end 

class Site < ActiveRecord::Base 

    belongs_to :user 

    has_many :site_servers 
    has_many :servers, :through => :site_servers 

    accepts_nested_attributes_for :site_servers, :allow_destroy => true 
    accepts_nested_attributes_for :servers, :allow_destroy => true 

    validates_presence_of :name, :on => :create, :message => "Name is required" 
end 

class Server < ActiveRecord::Base 
    attr_encrypted :password, :key => '393b79433f616f445f652a752d', :attribute => 'crypted_password' 

    belongs_to :user 

    has_many :site_servers 
    has_many :sites, :through => :site_servers 

    validates_presence_of :url, :on => :create, :message => "URL is required." 
    validates_presence_of :username, :on => :create, :message => "Username is required." 
    validates_presence_of :password, :on => :create, :message => "Password is required." 


    def name 
    username + "@" + url 
    end 

    def to_s 
    name 
    end 

end 

class SiteServer < ActiveRecord::Base 
    belongs_to :site 
    belongs_to :server 

    has_one :user, :through => :site 
end 

Et voici mon schéma:

ActiveRecord::Schema.define(:version => 20091203045550) do 

    create_table "servers", :force => true do |t| 
    t.string "url" 
    t.string "username" 
    t.string "crypted_password" 
    t.integer "port" 
    t.integer "user_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "site_servers", :force => true do |t| 
    t.integer "site_id" 
    t.integer "server_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "sites", :force => true do |t| 
    t.string "name" 
    t.string "url" 
    t.string "path" 
    t.integer "user_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "users", :force => true do |t| 
    t.string "username" 
    t.string "email" 
    t.string "crypted_password" 
    t.string "password_salt" 
    t.string "persistence_token" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

end 
+0

Collez également vos modèles. – bensie

Répondre

2

Avez-vous un champ caché pour le user_id sous forme de serveur? Si ce n'est pas le cas, la valeur ne sera pas renvoyée, même si vous avez réussi à la définir correctement. La ligne que vous avez commentée aurait fonctionné, si vous ajoutez un champ caché au formulaire.

@site.servers.build(:user_id => current_user.id) if @site.servers.empty? 

fait je aime l'idée de l'ID utilisateur dans la méthode de création mieux, car sinon vous introduisons la possibilité d'une personne élaboration leur propre formulaire de soumission et de créer des choses sous les ids des utilisateurs des autres. Je ne sais pas si la sécurité est un gros problème dans votre application, mais je ne fais jamais confiance à un identifiant d'utilisateur qui est envoyé à partir d'un formulaire.

+0

ahh. Je n'avais pas réalisé que j'avais besoin de faire ça pour persévérer. logique. Je vais remplir manuellement depuis que vous avez soulevé le problème de sécurité. Merci. – devth

+0

Euh ouais énorme problème de sécurité là-bas - ne fais jamais ça. – bensie

1

Je devine que le problème est dans votre action create. La nouvelle action construit juste des objets Ruby - vous devez vous assurer qu'il ya un code de construction similaire dans l'action create:

def create 
    @site = current_user.sites.build(params[:site]) 
    @site.save 
end 
+0

Merci pour la réponse. Je viens juste de coller ma méthode create ci-dessus. J'utilisais déjà le code exact que vous avez posté. Je pense que la raison en est que le serveur est créé en tant qu'enfant de site. Le site pense simplement qu'il doit maintenir la relation entre le site et le serveur, ce qu'il fait. Comment le site sait-il qu'il doit également indiquer au serveur le bon id_utilisateur? – devth

+0

Faut-il le faire manuellement? Semble un peu hackish, mais peut-être que je pourrais faire: @ site.servers.first.user_id = current_user.id dans ma méthode de création. – devth

+0

Je vois ce que vous dites maintenant, mais j'ai du mal à comprendre ce que vous essayez d'accomplir. Pourquoi utilisez-vous has_many: servers,: through =>: site_servers? Je ne comprends pas le but de la table de jointure. La façon dont je le vois, l'utilisateur devrait has_many: sites, Site devrait has_many: serveurs, et l'utilisateur devrait has_many: serveurs, à travers =>: sites. – bensie

Questions connexes