2009-09-01 4 views
1

Dites que j'ai beaucoup de blogs, et chaque blog has_many messages. Ceux-ci sont stockés dans 2 tables ("blogs" et "posts"). Est-il possible d'ajouter une colonne supplémentaire (par exemple scoped_id) à la table de blog qui stocke un ID, délimité par le blog.Rails: Scoped ID en plus de l'ID principal

Exemple

Blog: 1 
    - Posts 
    - id: 1, scoped_id: 1 
    - id: 2, scoped_id: 2 
    - id: 3, scoped_id: 3 
Blog: 2 
    - Posts 
    - id: 4, scoped_id: 1 
    - id: 5, scoped_id: 2 
    - id: 6, scoped_id: 3 

Je sais que counter_cache peut garder une trace du nombre de postes scope par le blog parent. Cependant, je ne veux pas que le scoped_id décrémente si un message est détruit.

Répondre

1

Votre meilleur pari serait de garder le dernier ID utilisé sur le blog, et le remplir via:

class Post < ActiveRecord::Base 
    … 
    before_create :populate_scoped_id 

    def populate_scoped_id 
    blog.increment!(:latest_scoped_post_id) 
    self[:scoped_id] = blog.latest_scoped_post_id 
    end 
    … 
end 

ou jazz comme ça.

Si la sauvegarde échoue, le compteur ne sera pas incrémenté, car tout est dans une énorme transaction (c'est, comme, totalement entreprise).

+0

Excellent. Merci! – Homar

+0

Ce code est vulnérable à une condition de concurrence qui peut entraîner la création de deux ou plusieurs entrées de blog ayant le même scoped_id lorsque le serveur traite deux demandes simultanément. Par exemple, considérons la séquence suivante: (1) Demande A lit latest_scoped_post_id x, (2) La requête B lit le même latest_scoped_post_id x, (3) Demande A définit scoped_id à x + 1, (4) Demande B définit scoped_id à x + 1 (identique à la demande A). – antinome

+0

Vous pourriez vous attendre à ce qu'une transaction protège contre des conditions de concurrence comme celle-ci, mais ce ne sera pas le cas, sauf si vous définissez le niveau d'isolation des transactions anormalement élevé (probablement une mauvaise idée de performance). – antinome

1

oui vous pouvez certainement ajouter une autre colonne, et si elle est moi, je ferais un rappel before_save pour sauver le scoped_id si c'est un new_record?

class Post < ActiveRecord::Base 
    ... 
    before_save :populate_scoped_id 

    def populate_scoped_id 
    assign_the_scoped_id_method if self.new_record? 
    end 
    ... 
end 

espère que cela aide =)

+0

Merci, mais comment vous assurer que le même scoped_id n'est jamais répété pour le blog parent? – Homar

+1

Je prendrais le plus grand scoped_id et l'incrémenterais de 1 (remplacer assign_the_scoped_id_method): self.scoped_id = Post.maximum (: scoped_id) + 1 – Staelen

+3

N'oubliez pas d'ajouter un index unique dans votre base de données: add_index: posts, [ : id,: scoped_id],: unique => true. Sinon, il pourrait y avoir (au moins en théorie) deux requêtes simultanées et vous pourriez vous retrouver avec le même scoped_id deux fois. –

Questions connexes