2009-06-14 6 views
0

Travailler sur un exemple simple de relations polymorphes double face en utilisant le plugin has_ ​​many_ polymorphs ActiveRecord. J'ai deux classes, "chats" et "chiens", qui peuvent avoir des "amitiés" les uns avec les autres, donc trois classes en tout: "chats", "chiens" et "amitiés". Un chat peut être ami avec un chien (oui, ça arrive!) Et bien sûr aussi avec d'autres chats. La même chose vaut pour les chiens. Voici mes modèles:Comment définir has_many_polymorphs Les paramètres CRUD reposfully

class Cat < ActiveRecord::Base 
    validates_presence_of :name 
end 

class Dog < ActiveRecord::Base 
    validates_presence_of :name 
end 

class Friendship < ActiveRecord::Base 
    belongs_to :left, :polymorphic => true 
    belongs_to :right, :polymorphic => true 

    acts_as_double_polymorphic_join(
    :lefts => [:cats, :dogs], 
    :rights => [:dogs, :cats] 
) 
end 

J'ai essayé pendant des jours pour obtenir ce travail et je dois manquer quelque chose d'évident. Lorsque je tente de créer une nouvelle amitié que je reçois:

NameError (wrong constant name cats): 
    (eval):7:in `before_save' 
app/controllers/friendships_controller.rb:45:in `create' 

ou

NameError (wrong constant name dogs): 
    (eval):7:in `before_save' 
app/controllers/friendships_controller.rb:45:in `create' 

Ceci est mon schema.rb:

ActiveRecord::Schema.define(:version => 20090613051350) do 
    create_table "cats", :force => true do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 
    create_table "dogs", :force => true do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 
    create_table "friendships", :force => true do |t| 
    t.integer "left_id" 
    t.string "left_type" 
    t.integer "right_id" 
    t.string "right_type" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 
end 

Je suis en train de créer une nouvelle "amitié" en faisant un POST à, par exemple,/cats/3/relations avec une route qui obtient left_type et left_id de l'URL et le right_type et right_id des paramètres POST. Le routage déclenche la méthode #create du contrôleur friendships_ correctement et les params résultant ressembler à ceci:

Parameters: { 
    "authenticity_token"=>"gG1eh2dXTuRPfPJ5eNapeDqJu7UJ5mFC/M5gJK23MB4=", 
    "left_type"=>"cats", 
    "right_type"=>"dogs", 
    "left_id"=>"3", 
    "right_id"=>"1" 
} 

Pour des raisons qui ne relèvent pas de cette question, je veux séparer entre « gauche » et « droits » dans de telle sorte que je puisse suivre à qui l'amitié a été postée (d'où les «gauches» et «droits»), mais peut-être mon modèle n'est pas la bonne façon d'accomplir cela? Ai-je mal compris le but du plugin has_ ​​many_ polymorphs? Voici l'action #create du contrôleur friendships_:

def create 
    @friendship= Friendship.new(
    :left_type => params[:left_type], 
    :left_id => params[:left_id], 
    :right_type => params[:right_type], 
    :right_id => params[:right_id] 
) 
    respond_to do |format| 
    if @friendship.save 
     format.xml { 
     render :xml => @friendship, 
     :status => :created, 
     :location => @friendship 
     } 
    else 
     format.xml { 
     render :xml => @friendship.errors, 
     :status => :unprocessable_entity 
     } 
    end 
    end 
end 

Et enfin mon routes.rb:

map.resources :friendships 

map.resources :cats do |cat| 
    cat.resources :friendships, :path_prefix => "/:left_type/:left_id" 
end 

map.resources :dogs do |dog| 
    dog.resources :friendships, :path_prefix => "/:left_type/:left_id" 
end 

Comme je l'ai dit, je l'ai passé beaucoup de temps sur mon propre pour essayer de comprendre ce mais la documentation qui existe est soit périmée, trop générale ou trop avancée - ou, dans certains cas, les trois à la fois. Ce n'est pas facile de commencer sur ce truc RoR, je peux vous le dire! Je sais qu'il y a des avantages réels de la maîtrise du RoR donc je vais persister, mais certains de ces casse-tête sont si mauvais que je commence à avoir un patch chauve. Je sais qu'il y a beaucoup de développeurs expérimentés de Ruby/Rails et j'espère que quelqu'un pourra sortir du bois et expliquer ce truc pour nous, simples mortels.

Merci à l'avance,

JS

Répondre

0

Une relation polymorphique devrait faire la plupart de ce dont vous avez besoin bien que si vos chats et chiens sont amis avec des cochons et que vous voulez savoir qui a initié l'amitié ma solution précédente est trop simpliste.

class Animal < ActiveRecord::Base 
    belongs_to :creatures, :polymorphic => true 
    named_scope :cats, :conditions => {:creature_type => 'Cat'} 
    named_scope :dogs, :conditions => {:creature_type => 'Dog'} 
    named_scope :pigs, :conditions => {:creature_type => 'Pig'} 
end 

class Cat < ActiveRecord::Base 
    has_many :friends, :as => :creatures 
end 

class Dog < ActiveRecord::Base 
    has_many :friends, :as => :creatures 
end 

class Pig < ActiveRecord::Base 
    has_many :friends, :as => :creatures 
end 

Cela peut ne pas être ce que vous voulez, mais il vous permettra d'appeler cat.friends et cat.friends.dogs, cat.friends.pigs etc.

Vous pouvez ajouter has_many les associations afin que vous puissiez appelez cat.dogs et cat.pigs directement.

class Cat < ActiveRecord::Base 
    has_many :friends, :as => :creatures 
    has_many :dogs, :through => :animal 
    has_many :pigs, :through => :animal 
end 

Je ne sais pas si c'est ce que vous cherchez, mais je pense qu'il est un moyen plus simple d'aller simple est toujours mieux.

0

je serais probablement opter pour un modèle de chat et de chien, puis utiliser une association has_and_belongs_to_many?

class Cat < ActiveRecord::Base 
    has_and_belongs_to_many :dogs 
end 

class Dog < ActiveRecord::Base 
    has_and_belongs_to_many :cats 
end 

Ensuite, la table de jointure ressemblerait à ceci ...

create_table "cats_dogs", :id => false, :force => true do |t| 
    t.integer "cat_id" 
    t.integer "dog_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
end 

Vous seriez en mesure d'appeler cat.dogs et dog.cats de trouver des 'amitiés'.

+0

Merci James, cela ressemble à une solution beaucoup plus simple! Mais ne commencerait-il pas à devenir un peu maladroit quand j'ai plus de deux classes de base? Qu'est-ce que je devais ajouter une troisième classe, disent les porcs, aux deux autres? En outre, ce modèle ne me permettrait pas de voir quelle partie a été l'initiateur de la relation (les «gauches» dans mon exemple ci-dessus), ou est-ce que j'ai mal compris quelque chose? –

Questions connexes