如何在Rails中实现计数器缓存?

时间:2010-06-02 07:44:00

标签: ruby-on-rails one-to-many counter-cache

我有一个帖子控制器和一个评论控制器。 Post有很多评论,评论属于Post。 设置了关联,并启用了counter_cache选项:

#Inside post.rb
has_many :comments

#Inside comment.rb
belongs_to :post, :counter_cache => true

我的comments_count表格中有posts列默认为零,因此:

add_column :posts, :comments_count, :integer, :default => 0

在我的评论控制器的create操作中,我有以下代码:

def create
  @posts = Post.find(params[:post_id])
  @comment = @post.comments.build(params[:comment])
  if @comment.save
    redirect_to root
  else
    render :action => 'new'
  end
end

我的问题:调用@comment.save时,出现以下错误:

ArgumentError in CommentsController#create

wrong number of arguments (2 for 0)

从comment.rb中删除:counter_cache => true完全解决了这个问题,所以我假设这是造成这个模糊错误的原因。我在这里错过了什么? 我怎样才能保存我的评论,并且仍然可以使用rails来处理我的帖子中的counter_cache?

谢谢!


更新 - 附加应用程序跟踪:

/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:987:in `update_all'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:987:in `update_counters_without_lock'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/locking/optimistic.rb:176:in `update_counters'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:1006:in `increment_counter'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/associations.rb:1367:in `belongs_to_counter_cache_after_create_for_feed_entry'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:178:in `send'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:178:in `evaluate_method'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:166:in `call'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:93:in `run'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:92:in `each'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:92:in `send'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:92:in `run'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/callbacks.rb:276:in `run_callbacks'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/callbacks.rb:344:in `callback'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/callbacks.rb:267:in `create'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:2915:in `create_or_update_without_callbacks'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/callbacks.rb:250:in `create_or_update'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:2573:in `save_without_validation'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/validations.rb:1090:in `save_without_dirty'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/dirty.rb:79:in `save_without_transactions'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:229:in `send'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:229:in `with_transaction_returning_status'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:182:in `transaction'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:228:in `with_transaction_returning_status'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:196:in `save'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:196:in `save'
/Users/yuval/Sites/rails/blog/app/controllers/comments_controller.rb:6:in `create'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:1331:in `send'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:1331:in `perform_action_without_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:617:in `call_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/core_ext/benchmark.rb:17:in `ms'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/core_ext/benchmark.rb:17:in `ms'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/rescue.rb:160:in `perform_action_without_flash'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/flash.rb:151:in `perform_action'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:532:in `send'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:532:in `process_without_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:606:in `process'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:391:in `process'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:386:in `call'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/routing/route_set.rb:438:in `call'

请注意,唯一不必直接使用Rails框架的行是:

/Users/yuval/Sites/rails/blog/app/controllers/comments_controller.rb:6:in `create'

第6行如下:

if @comment.save

编辑2: 当我为StackOverflow编写简化示例时,@posts / @post是我的错误,我的实际应用程序还没有没错。

检查@comment,它似乎完全有效 - 它完全返回我期望它 - 一个新的评论实例,包含我用build传递给它的任何信息。它只会在调用save方法时爆炸。

感谢您提出的所有建议。还有其他想法吗?

3 个答案:

答案 0 :(得分:9)

我用你的代码运行了一个示例rails应用程序,这对我来说都很好。

我建议稍微调试一下像hurikhan77建议的那样,看看它是否仅仅是@posts / @post问题。

另外,尝试在控制台中创建一个帖子和评论,其中包含一些非常简单的内容,以确定它是否有效。

$ ruby script/console

# add whatever fields are necessary to create     
> @p = Post.create(:title => "TestPost1")
  # => #<Post id: 3, ...

# again, add whatever is necessary to create
> @c = @p.comments.create(:comment => "TestComment1")
  # => #<Comment id: 8, ...

> Post.find(:last).comments_count
  # => 1

看看能得到什么。

/ JP

答案 1 :(得分:2)

这可能完全不合适,但你使用@posts然后@post?

答案 2 :(得分:2)

  

中的ArgumentError   CommentsController#创建

     

错误的参数数量(2为0)

您收到此错误,因为@comment不是您期望的对象。尝试通过插入:

来调试它
logger.debug @comment.inspect

你会看到意想不到的东西,至少应该引起一阵眉毛。这应该是您为Post.find(...)分配给@posts但后来尝试使用@post的clou。