Стремительная загрузка самого последнего элемента отношения «есть много» - PullRequest
0 голосов
/ 31 мая 2011

У меня есть две модели: Conversation и Message.Сообщение принадлежит_ разговору, а сообщение разговора имеет_много:

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

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

У меня есть интерфейс, который собирается перечислить все разговоры, но я также хочу включить «самое последнее» сообщение, связанное с беседой.через eager-loading.

Нужно ли создавать новое отношение has_one или own_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' не может быть нулевым: INSERT INTO `разговор '(` last_message_id`, `updated_at`,` create_at`) VALUES (NULL,' 2011-05-31 16:57: 11 ',' 2011-05-31 16:57:11 ')

Ответы [ 2 ]

1 голос
/ 01 июня 2011

Вы можете использовать другую ассоциацию:

# 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_message и messages и считаются независимыми ассоциациями.Если вы используете conversation.messages, сообщения будут загружены из базы данных.И если вы измените атрибут last_message, он не повлияет на messages.last до перезагрузки.

Редактировать: На самом деле, согласно журналу, ActiveRecord по-прежнему загружает все разговоры 'Сообщения.Возможно, потому что он не может «LIMIT 1», как это происходит, когда он не загружен.

Таким образом, с точки зрения запросов SQL, это решение похоже на простое использование Conversation.includes(:messages).Но, возможно, Rails не обрабатывает дополнительные результаты при использовании ассоциации has_one.

0 голосов
/ 31 мая 2011

В каком смысле вы имеете в виду ленивую загрузку? Только что самое последнее сообщение не загружается при загрузке разговора? Попробуйте это:

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.last. Таким образом, если сообщение будет добавлено между вызовом @ разговор.messages и @ разговор.messages.last, вы не получите действительно последний. Но я предполагаю, что это, вероятно, хорошо?

...