2009-05-24 7 views
3

J'ai ajouté un cache de compteur mais je n'arrive pas à le mettre à jour. Mais je peux mettre à jour le parent - le modèle Blog Post en ajoutant un nouveau post de blog - et je peux mettre à jour l'enfant - Modèle de commentaires - en ajoutant un nouveau commentaire. Le cache de compteur est censé garder une trace du nombre total de commentaires par article de blog en mettant à jour automatiquement le champ blog_posts.comments_count. Je vais décrire certaines des étapes que j'ai traversé et j'espère que quelqu'un remarquera quelque chose que j'ai mal fait. Le vidage de schéma est à la fin.le cache du compteur ne se met pas à jour mais je peux enregistrer dans le parent et l'enfant

J'ai un modèle post Blog:

class Post < ActiveRecord::Base 
    set_table_name("blog_posts") 
    belongs_to :author, :class_name => "User", :foreign_key => 'author_id' 
    has_many :comments, :class_name => "Comment", 
    :foreign_key => 'post_id', :order => "created_at desc", :dependent => :destroy 
    has_many :categorizations 
    has_many :categories, :through => :categorizations 
    named_scope :recent, :order => "created_at desc", :limit => 5 

end 

et un modèle Commentaires avec un counter_cache réglé sur le modèle post:

class Comment < ActiveRecord::Base 
    belongs_to :post, :class_name => "Post", :foreign_key => "post_id", :counter_cache => true 
    belongs_to :author, :class_name => "User", :foreign_key => "author_id" 
end 

J'ai créé une migration pour ajouter la colonne de counter_cache aux blog_posts table:

class AddCommentCounter < ActiveRecord::Migration 
    def self.up 
    add_column :blog_posts, :comments_count, :integer, :limit => 4, :default => 0, :null => false 
    Post.find(:all).each do |post| 
     current_count = post.comments.size 
     post.update_attribute(:comments_count, current_count) 
    end 
    end 

    def self.down 
    remove_column :blog_posts, :comments_count 
    end 
end 

La migration ne parvient pas à mettre à jour compter. C'est toujours zéro.

J'ai ouvert la console Rails pour essayer de update_attribute manuellement:

Loading development environment (Rails 2.3.2) 

>> p = Post.find 1 
p = Post.find 1 

=> #<Post id: 1, title: "test", content: "test", author_id: 1, status: "ok", created_at: "2009-05-21 19:27:14", updated_at: "2009-05-24 07:02:35", comments_count: 0> 

>> p.comments 
p.comments 

=> [#<Comment id: 5, post_id: 1, author_id: 1, content: "Fifth Comment", status: "ok", created_at: "2009-05-24 07:08:56", updated_at: "2009-05-24 07:08:56">, #<Comment id: 4, post_id: 1, author_id: 1, content: "Fourth Comment", status: "ok", created_at: "2009-05-24 07:05:32", updated_at: "2009-05-24 07:05:32">, #<Comment id: 3, post_id: 1, author_id: 1, content: "Third Comment", status: "ok", created_at: "2009-05-24 06:34:59", updated_at: "2009-05-24 06:34:59">, #<Comment id: 2, post_id: 1, author_id: 1, content: "Second Comment", status: "ok", created_at: "2009-05-24 05:20:43", updated_at: "2009-05-24 05:20:43">, #<Comment id: 1, post_id: 1, author_id: 1, content: "First Comment", status: "ok", created_at: "2009-05-21 19:27:14", updated_at: "2009-05-21 19:27:14">] 


>> p.comments.size 
p.comments.size 

=> 5 

>> p.comments_count 
p.comments_count 

=> 0 

>> p.update_attribute(:comments_count, 5) 
p.update_attribute(:comments_count, 5) 

=> true 

>> p.comments_count 
p.comments_count 

=> 5 

>> p.save 
p.save 

=> true 

Mais quand je regarde dans la base de données comments_count = 0.

Toutes les idées seraient plus joyeusement apprécié.

Mon schema.db ressemble à ceci:

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

    create_table "blog_posts", :force => true do |t| 
    t.string "title",   :limit => 100, :default => "", :null => false 
    t.text  "content",          :null => false 
    t.integer "author_id",      :default => 0, :null => false 
    t.string "status",   :limit => 20, :default => "", :null => false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.integer "comments_count",    :default => 0, :null => false 
    end 

    add_index "blog_posts", ["author_id"], :name => "index_blog_posts_on_author_id" 

    create_table "categories", :force => true do |t| 
    t.string "name",  :limit => 50, :default => "", :null => false 
    t.string "short_name", :limit => 30, :default => "", :null => false 
    t.string "description",    :default => "", :null => false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "categories_posts", :force => true do |t| 
    t.integer "category_id", :null => false 
    t.integer "post_id",  :null => false 
    end 

    add_index "categories_posts", ["category_id"], :name => "index_categories_posts_on_category_id" 
    add_index "categories_posts", ["post_id"], :name => "index_categories_posts_on_post_id" 

    create_table "comments", :force => true do |t| 
    t.integer "post_id",     :default => 0, :null => false 
    t.integer "author_id",    :default => 0, :null => false 
    t.text  "content",         :null => false 
    t.string "status",  :limit => 25, :default => "", :null => false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "sessions", :force => true do |t| 
    t.string "session_id", :default => "", :null => false 
    t.text  "data" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id" 
    add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at" 

    create_table "users", :force => true do |t| 
    t.string "username",  :limit => 25, :default => "", :null => false 
    t.string "hashed_password", :limit => 40, :default => "", :null => false 
    t.string "first_name",  :limit => 25, :default => "", :null => false 
    t.string "last_name",  :limit => 40, :default => "", :null => false 
    t.string "email",   :limit => 50, :default => "", :null => false 
    t.string "display_name", :limit => 25, :default => "", :null => false 
    t.integer "user_level",  :limit => 3, :default => 0, :null => false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

end 
+0

Y a-t-il une raison particulière pour laquelle la table de votre modèle Post ne peut pas être nommée "posts"? Et pourquoi spécifiez-vous manuellement le class_name et la foreign_key partout? Il semble que vous ne deviez le faire que pour votre modèle Author qui est soutenu par une table "users". Il semble y avoir beaucoup de combats contre les défauts de Rails en cours. –

+0

Je suis un tutoriel qui vous montre comment contourner les paramètres par défaut si nécessaire. –

+0

OK, mais pour la plupart de votre exemple, vous n'avez pas besoin de le faire. –

Répondre

5

Jetez un oeil sur le code mis à jour railscasts episode 23 sur counter_cache.

Les attributs du compteur sont attr_readonly. Peut-être que update-counters est ce que vous devez utiliser à la place des attributs de mise à jour dans votre migration?

+0

Bonne idée. Cela n'a pas fonctionné. Échec de la migration de la migration pour pouvoir utiliser: Post.update_counters (post.id,: comments_count => current_count). Aucune erreur ou quoi que ce soit - n'a pas mis à jour le comments_counter. –

+1

Eh bien, il n'y a pas de règle que vous avez seulement un problème. – srboisvert

+0

Très vrai. Je revérifierai à partir de zéro une autre fois. –