2009-12-02 7 views
0

Rails, pour compter automatiquement les associations, vous faites:associations de rails transitif et le nombre magique

class Script 
    has_many :chapters 
end 
class Chapter 
    belongs_to :script 
end 

et vous ajoutez une colonne chapters_count dans le modèle de script.

Maintenant, que faire si vous voulez compter le nombre de paragraphes dans un script sans avoir une clé script_id dans le modèle de paragraphe?

class Script 
    has_many :chapters 
    has_many :paragraphs # not complete 
end 
class Chapter 
    has_many :paragraphs 
    belongs_to :script 
end 
class Paragraph 
    belongs_to :chapter 
end 

Comment comptez-vous de script automatiquement associé au paragraphe et les compte en utilisant le compte automatique des rails?

Répondre

1

Vous êtes sur la bonne voie. Mais d'abord vous devez adresser une petite erreur. Rails ne mettra pas à jour un cache de compteur sauf si vous le lui demandez.

class Chapter 
    belongs_to :script, :counter_cache => true 
end 

Mettre automatiquement à jour @ script.chapter_count avant la création et après la destruction de tous les chapitres associés. Malheureusement, les choses ne sont pas si simples lorsqu'il s'agit de relations. Vous devrez mettre à jour le compteur de paragraphes du script associé via des rappels dans le modèle Paragraphe. NB: Ce qui suit suppose que vous souhaitiez conserver un compteur de paragraphes dans le chapitre également. Commencez par appliquer la même théorie au modèle Chapter et une colonne de comptage de paragraphes à la table Script.

class PrepareForCounterCache < ActiveRecord::Migration 
    def self.up 
    add_column :scripts, :paragraphs_count, :integer, :default => 0 
    add_column :chapters, :paragraphs_count, :integer, :default => 0 

    Chapter.reset_column_information 
    Script.reset_column_information 

    Chapter.find(:all).each do |c| 
     paragraphs_count = c.paragraphs.length 
     Chapter.update_counters c.id, :paragraphs_count => paragraphs_count 
     Script.update_counters c.script_id, :paragraphs_count => paragraphs_count 
    end 
    end 
    def self.down 
    remove_column :scripts, :paragraphs_count 
    remove_column :chapters, :paragraphs_count 
    end 
end 

Maintenant, pour mettre en place les relations:

class Script 
    has_many: chapters 
    has_many: paragraphs, :through => :chapters 
end 

class Chapter 
    has_many: paragraphs 
    belongs_to :script, :counter_cache => true 
end 

class Paragraph 
    belongs_to :chapter, :counter_cache => true 
end 

Tout ce qui reste est de dire le paragraphe mettre à jour les compteurs de paragraphe dans le script comme un rappel.

class Paragraph < ActiveRecord::Base 
    belongs_to :chapter, :counter_cache => true 
    before_save :increment_script_paragraph_count 
    after_destroy, :decrement_script_paragraph_count 

    protected 
    def increment_script_paragraph_count 
    Script.update_counters chapter.script_id, :paragaraphs_count => 1 
    end 
    def decrement_script_paragraph_count 
    Script.update_counters chapter.script_id, :paragaraphs_count => -1 
    end 
end 
0

La façon rapide et simple, sans l'aide d'un cache est de faire:

class Script 
    has_many :chapters 
    has_many :paragraphs, :through => :chapters 
end 

script = Script.find(1) 
puts script.paragraphs.size #get the count 
+0

C'est étrange, je pensais que l'association transitive ne fonctionne pas parce que script.paragraphs.size est egal à 0. Mais script.paragraphs.length est correct. Mais j'aimerais vraiment tiouse paragraphes_count, le nombre de Rails automatique. – MickaelFM

+0

Ceci est une fonction de rails (une méthode ajoutée par has_many). counter_cache ne fonctionne pas sur un has_many: through, car le cache est implémenté du côté belongs_to. Vous devrez écrire le vôtre, voici un exemple: http://www.ruby-forum.com/topic/138094#614246 – MattMcKnight