2016-03-11 3 views
1

J'ai posé cette question différemment, mais supprimé pour tenter plus de clarté.Rails has_many: à travers avec unicité

J'ai un modèle Article. Il a beaucoup de contacts, à travers:: article_contacts.

J'ai un modèle de contact. Il a beaucoup d'articles, à travers:: article_contacts.

Ce dont j'ai besoin, c'est que chaque objet Contact soit unique, mais puisse être associé à différents articles. Ma dernière question a amené les gens à me montrer comment afficher uniquement des contacts uniques, ou à valider le modèle de jointure, mais ce n'est pas ce dont j'ai besoin.

j'ai besoin, par exemple, des tables comme les suivantes:

Article 
id: 1, name: "Whatever", content: "Whatever" 
id: 2, name: "Again, whatever", content: "Whateva" 

Contact 
id: 1, email: "[email protected]" 
id: 2, email: "[email protected]" 

ArticleContact 
id: 1, article_id: 1, contact_id: 1 
id: 2, article_id: 1, contact_id: 2 
id: 3, article_id: 2, contact_id: 1 

Alors, quand je construis l'association dans mon contrôleur de l'article dans la nouvelle action et j'appelle @ article.save dans l'action create, I obtenir un insert du nouvel article, un insert du contact et un insert de l'article_relationship. Génial. MAIS, à l'article 2, si j'ajoute le même courriel au formulaire de contact, je ne veux pas créer un autre contact avec le même courriel. Mais je veux (comme vous le voyez avec le troisième ID dans ArticleContact ci-dessus) à créer. Mais chaque appel à @ article.save le fait. J'ai essayé first_or_initialize et < < dans la collection, mais il crée toujours plusieurs fois et si j'ai une validation, cela signifie que je ne peux pas créer la relation ArticleContact car le contact est unique. Je pourrais éventuellement avoir une liste déroulante avec les contacts, mais je suspecte que ce sera long, donc je préfère simplement entrer un email dans un formulaire et avoir le code vérifier qu'il est unique et si oui, il suffit de créer le joindre une relation en utilisant l'identifiant existant.

Cela doit être plus facile que je ne conçois, mais je ne trouve pas un seul article qui le démontre n'importe où.

Mise à jour avec le code par requête, bien que, encore une fois, je n'ai pas le code pour créer seulement un contact unique et associer la relation avec un existant. C'est ce qui me manque donc ce code ne vous montrera que ce que je sais déjà fonctionne et pas comment arriver à ce que je veux :).

ArticleController:

def new 
    @article = @business.articles.build 
    authorize @business 
    @article.attachments.build 
    @article.contacts.build 
end 

def create 
    @article = @business.articles.new(article_params) 
    authorize @business 

    respond_to do |format| 
    if @article.save 
     format.html { redirect_to business_article_path(@business, @article), notice: "Knowledge created." } 
    else 
     format.html { render 'new' } 
    end 
    end 

end 

modèles ont la norme has_many: thruogh et appartient. Je peux le montrer, mais ils sont la bonne façon. Voir est juste un simple_form STANDING le contact:

<%= f.simple_fields_for :contacts, class: "form-inline" do |contact| %> 
    <%= contact.input :first_name, label: "Contact First Name" %> 
    <%= contact.input :last_name, label: "Contact Last Name" %> 
    <%= contact.input :email, label: "Contact Email" %> 
    <% end %> 
+0

Ajout votre contrôleur, et les modèles le code des vues aiderait à diagnostiquer le problème. – Dharam

+0

Je peux, mais ceux-ci sont extrêmement plaque de la chaudière. Je soupçonne que le code que j'ai fait exactement ce qu'il est supposé faire, c'est-à-dire créer une association et enregistrer, enregistrer le contact et l'association. J'en ai besoin pour être plus complexe et je ne sais pas comment, mais je vais y mettre la plaque de chaudière :). – Art

+0

Comment affectez-vous 'contact' à' article' dans 'articles_controller'? – Dharam

Répondre

1

Vous devriez respecter l'unicité, juste au cas où:

# contact.rb 
class Contact 
    ... 
    validates_uniqueness_of :email 
    ... 
end 

Mais dans votre contrôleur, vous pouvez faire:

# articles_controller.rb 
def create 
    ... 
    # we can rely on it's uniqueness 
    contacts << Contact.find_or_create_by(email: param[:email) 
    ... 
end 

Ou tout correspond le mieux à vos besoins.

Espérons que cela aide!

+0

Merci pour la réponse. Je ne veux pas imposer l'unicité sur la soumission du formulaire. Je sais que les gens vont soumettre le même courriel plus d'une fois. Si je valide sur: email, que j'ai essayé, je viens d'obtenir l'erreur de formulaire standard indiquant que l'e-mail est déjà pris. Je connais. J'en ai besoin pour accepter un doublon lors de la soumission d'un formulaire, mais ensuite, sur create, ajoutez simplement ce paramètre. Votre création semble correcte. J'ai essayé cela, mais il ajoute deux fois parce que @ article.save l'enregistre en premier. – Art

+0

Donc, j'ai dû supprimer contacts_attributes de la soumission du formulaire afin que whitelisted_params = article_params, puis supprimer des paramètres de la liste blanche. Cela m'a permis d'utiliser ceci pour construire le contact séparément et le garder unique. Je vais confirmer demain mais jusqu'à présent, c'est la seule façon de garder @ article.save de sauver un contact. – Art

1

donnez votre articleContactez une validation avec une portée.

validates :article_id, unique {scope: :contact_id} 

Cela vous évitera d'avoir des contacts d'article qui sont exactement les mêmes.

lorsque vous créez un contact, essayez:

contact = Contact.where(email: "[email protected]:").first_or_create 

dans contact.rb

validates :email, uniqueness: true 
+0

Cela fonctionnerait et j'ai essayé, mais le @ article.save insère réellement le contact pour moi. Je n'ai pas l'occasion de le construire sur le côté. C'est ma confusion. – Art

+0

personnellement, je le ferais au lieu de construire le contact avant pour cette raison même. Créez-le vous-même à l'intérieur si @ article.save et débarrassez-vous de la construction. devrait marcher. – toddmetheny

0

Vous pouvez essayer cela dans la méthode create

verified_contacts = [] 

@article.contacts.each do |contact| 
    existing_contact = Contact.find_by(email: contact.email) 
    verified_contacts << (existing_contact || contact) 
end 

@article.contacts = verified_contacts