Подтвердить что ты не робот

Ассоциации Rails has_one Последняя запись

У меня есть следующая модель:

class Section < ActiveRecord::Base
  belongs_to :page
  has_many :revisions, :class_name => 'SectionRevision', :foreign_key => 'section_id'
  has_many :references

  has_many :revisions, :class_name => 'SectionRevision', 
                       :foreign_key => 'section_id'

  delegate :position, to: :current_revision

  def current_revision
    self.revisions.order('created_at DESC').first
  end
end

Где current_revision - это последний созданный revision. Можно ли превратить current_revision в ассоциацию, чтобы я мог выполнять запрос типа Section.where("current_revision.parent_section_id = '1'")? Или я должен добавить столбец current_revision в мою базу данных, а не пытаться создать его практически или через ассоциации?

4b9b3361

Ответ 1

Я понимаю, что вы хотите получить разделы, в которых последняя ревизия каждого раздела имеет parent_section_id = 1;

У меня такая же ситуация, во-первых, это SQL (пожалуйста, подумайте, что категории как разделы для вас, сообщения как ревизии и user_id как parent_section_id -sorry, если я не переведу код в вашу пользу, но я должен идти ):

SELECT categories.*, MAX(posts.id) as M
FROM `categories` 
INNER JOIN `posts` 
ON `posts`.`category_id` = `categories`.`id` 
WHERE `posts`.`user_id` = 1
GROUP BY posts.user_id
having M = (select id from posts where category_id=categories.id order by id desc limit 1)

И это запрос в Rails:

Category.select("categories.*, MAX(posts.id) as M").joins(:posts).where(:posts => {:user_id => 1}).group("posts.user_id").having("M = (select id from posts where category_id=categories.id order by id desc limit 1)")

Это работает, это уродливо, я думаю, что лучший способ - "вырезать" запрос, но если у вас слишком много разделов, которые были бы проблемой во время цикла их прохождения; вы также можете разместить этот запрос в статическом методе, а также, ваша первая идея, иметь ревизию_id внутри вашей таблицы разделов, поможет оптимизировать запрос, но откажется от нормализации (иногда это необходимо), и вам придется обновляя это поле, когда новая редакция создается для этого раздела (так что если вы собираетесь делать много изменений в огромной базе данных, возможно, это будет плохая идея, если у вас медленный сервер...)

UPDATE Я вернулся, я делал несколько тестов и проверял:

def last_revision
    revisions.last
end

def self.last_sections_for(parent_section_id)
  ids = Section.includes(:revisions).collect{ |c| c.last_revision.id rescue nil }.delete_if {|x| x == nil}

  Section.select("sections.*, MAX(revisions.id) as M")
         .joins(:revisions)
         .where(:revisions => {:parent_section_id => parent_section_id})
         .group("revisions.parent_section_id")
         .having("M IN (?)", ids)
end

Я сделал этот запрос и работал с моими таблицами (надеюсь, что я правильно назвал параметры, это тот же самый запрос Rails, но я изменяю запрос в поиске для оптимизации); следить за группой; включение делает его оптимальным в больших наборах данных, и жаль, что я не мог найти способ установить связь с has_one, но я бы пошел на это, но также передумал поле, которое вы упомянули в начале.

Ответ 2

Чтобы получить последнее из has_many, вы хотели бы сделать что-то похожее на @jvnill, за исключением добавления области с упорядочением к ассоциации:

has_one :current_revision, -> { order created_at: :desc }, 
  class_name: 'SectionRevision', foreign_key: :section_id

Это гарантирует, что вы получите самую последнюю версию из базы данных.

Ответ 3

Вы можете изменить его на ассоциацию, но, как правило, упорядочение для ассоциации has_one или belongs_to всегда интерпретируется неправильно при использовании в запросах. В вашем вопросе, когда вы превратите это в ассоциацию, это будет

has_one :current_revision, class_name: 'SectionRevision', foreign_key: :section_id, order: 'created_at DESC'

Проблема заключается в том, что когда вы пытаетесь объединить это с другими запросами, это обычно приводит к неправильной записи.

>> record.current_revision
   # gives you the last revision
>> record.joins(:current_revision).where(section_revisions: { id: 1 })
   # searches for the revision where the id is 1 ordered by created_at DESC

Поэтому я предлагаю вам вместо этого добавить current_revision_id.