铁轨上的红宝石-急切地装载a的最新物品有很多关系



我有两个模型:ConversationMessage。一条消息属于一个对话,而一个对话有_条消息:

# conversation.rb
class Conversation < ActiveRecord::Base
  has_many :messages
end
# message.rb
class Message < ActiveRecord::Base
  belongs_to :conversation
end

我有一个将列出所有对话的界面,但我也想通过热切加载包含与对话相关的"最新"消息。

我需要在对话和将跟踪最新消息的消息之间创建一个新的has_one或belongs_to关系吗?或者有没有一种方法可以通过使用联接/包含的作用域来实现这一点?

编辑:问题是我不希望在这个循环的每次迭代中都执行SQL查询:

# controller
@conversations = Conversation.all
# view
@conversations.each do |conversation|
  most_recent_message = conversation.messages.last
  # ...
end

编辑2:我还尝试过以下操作,但没有成功。目标是向对话表中添加一个last_message_id列,使其能够引用最后添加的消息。

# migration
add_column :conversations, :last_message_id, :integer
# conversation.rb
belongs_to :last_message, :class_name => 'Message'
# message.rb
after_create :set_last_message_on_conversation
def set_last_message_on_conversation
  self.conversation.last_message = self
  self.conversation.save!
end

但是,这会导致SQL错误,因为创建会话时last_message_id为null。(我希望这一切都发生在一个事务中,并希望在事务完成之前更新last_message_id,但我认为这是一个MySQL/MyISAM问题,不使用事务。)

ActiveRecord::StatementInvalid:Mysql::错误:列"last_message_id"不能为null:INSERT INTO"conversations"("last_mmessage_id"、"updated_at"、"created_at")VALUES(null,"2011-05-31 16:57:11"、"2011-05/31 16:57:12")

您可以使用另一个关联:

# conversation.rb
class Conversation < ActiveRecord::Base
  has_many :messages
  has_one :last_message, :class_name => "Message", :order => "created_at DESC"
end
# controller
@conversations = Conversation.includes(:last_message)
# view
@conversations.each do |conversation|
  most_recent_message = conversation.last_messages
  # ...
end

请注意,last_messagemessages被视为独立的关联。如果使用conversation.messages,则消息将从数据库加载。如果更改last_message的属性,则在重新加载之前不会影响messages.last

编辑:实际上,根据日志,ActiveRecord仍然加载所有对话的消息。可能是因为它不能像不急于加载时那样"限制1"。

因此,就SQL请求而言,这个解决方案似乎相当于简单地使用Conversation.includes(:messages)。但是也许Rails在使用has_one关联时不会处理额外的结果。

在什么意义上说懒惰加载?只是在加载对话时没有加载最新的消息?试试这个:

class Conversation < ActiveRecord::Base
  has_many :messages, :order => "created_at"
end

然后你可以打电话给

@conversation.messages.last

它正在执行类似的SQL

SELECT "messages".* FROM "messages" WHERE ("messages".conversation_id = 129) ORDER BY created_at DESC LIMIT 1

在你真正要求最后一条信息的时候。

重要信息:如果在执行操作期间在此之前调用过@conversation.messages,则它可能已经加载了所有消息,因此在调用@conversaction.messages.last时可能不会再次访问数据库。因此,如果在对@converstation.messages和@conversation.messages.last的调用之间添加了消息,则不会得到真正的最后一条消息。但我想这可能没关系吧?

相关内容

  • 没有找到相关文章

最新更新