按has_many的属性查找

时间:2009-11-23 22:34:49

标签: ruby-on-rails ruby

我必须举起双手,宣布我完全被这一个难住了!

我有以下型号:

Chat:
  has_many :messages

Message:
  belongs_to :chat, :counter_cache => true
  belongs_to :authorable, :polymorphic => true

User:
  has_many :messages, :as => :authorable
  has_many :chats, :through => :messages, :uniq => true

Guest:
  has_many :messages, :as => :authorable

我正在尝试在Chats上写一个named_scope给我“无人接听”的聊天(未答复意味着没有任何用户发布的聊天消息) - 到目前为止我只是设法绕过很多圈子!

任何帮助都会非常非常感谢! fwiw如果它变得更容易(甚至可能!),我并不特别喜欢它是一个命名的范围。

谢谢, 灰

2 个答案:

答案 0 :(得分:3)

命名范围的关键是将它们放在它们将返回的模型中。要获得未答复的聊天记录,您的命名范围应该放在聊天模型中。不幸的是,通过查找关联为空的情况,您并不是很容易。

使用命名范围执行此操作涉及LEFT / RIGHT OUTER连接和GROUP_BY运算符。它不会很漂亮,也不比编写自己的SQL

更好

您可能会发现使用计数器缓存更容易。但是,您的多态关联可能意味着直接计数器缓存也不起作用。

这个问题有点不清楚,没有答复的是那些没有消息的人,或者只是那些没有用户留言的人(只有客人留言的聊天仍然被认为没有答案?

如果它是前者而不是简单的计数器缓存,那么其他方面你还需要做更多的工作。

两种情况的通用代码:

使用此迁移在名为message_count的聊天表中添加一列:

class AddCounterCache < ActiveRecord::Migration
  def self.up
    add_column :chats, :message_count, :integer, :default => 0
  end

  def self.down
    remove_column :chats, :message_count
  end
end

然后在聊天模型中创建命名范围。

class Chat < ActiveRecord::Base
  ...
  named_scope :unanswered, :conditions => {:message_count => 0}
end

未答复聊天有0条消息的唯一代码

class Message < ActiveRecord::Base
  belongs_to :chat, :counter_cache => true
end

针对未应答的聊天可以包含来宾而非用户创作的消息的唯一代码:

我们只希望在某些情况下更新计数器缓存,因此我们需要覆盖ActiveRecord用于递增计数器缓存的方法,以便它只在我们需要时触发。 Rails提供了一种方便的方法来重命名方法,并通过ActiveSupport's alias_method_chain将它们包装在其他方法中。因此,此代码创建新方法,仅在必要时才触发用于更新计数器缓存的现有方法。然后alias_method_chain用于重命名方法,以便调用我们的新方法来代替ActiveRecord提供的方法。

class Message < ActiveRecord::Base
  belongs_to :chat, :counter_cache => true

  def belongs_to_counter_cache_after_create_for_chat_with_users_only
    if authorable_type == "User"
      belongs_to_counter_cache_after_create_for_chat_without_users_only
    end
  end

  def belongs_to_counter_cache_before_destroy_for_chat_with_users_only
    if authorable_type == "User"
      belongs_to_counter_cache_before_destroy_for_chat_without_users_only
    end
  end

  alias_method_chain :belongs_to_counter_cache_before_destroy_for_chat, :users_only
  alias_method_chain :belongs_to_counter_cache_after_create_for_chat, :users_only

end

完成所有这些。 Chat.unanswered会列出符合条件的所有聊天记录。您还可以获得不需要第二个查询来获取聊天中的消息数量的奖励。

答案 1 :(得分:1)

你可以在has_many模型本身上定义named_scope。

Chat.messages.unanswered

或者,您可以在SQL中编写named_scope,这样您就可以进行Chat.unanswered,但这对我来说感觉就像是错误的api。

更多示例:http://blog.peelmeagrape.net/2008/6/21/named_scope-is-super-awsome-with-has_many