ассоциации переходных рельсов и магический счет - PullRequest
0 голосов
/ 02 декабря 2009

В Rails для автоматического подсчета ассоциаций вы делаете:

class Script
  has_many :chapters
end
class Chapter
  belongs_to :script
end

и вы добавляете столбец chapters_count в модель Script.

А что если вы хотите посчитать количество абзацев в скрипте без ключа script_id в модели абзаца?

class Script
  has_many :chapters
  has_many :paragraphs # not complete
end
class Chapter
  has_many :paragraphs
  belongs_to :script
end
class Paragraph
  belongs_to :chapter
end

Как автоматически связать скрипт с абзацем и посчитать его, используя автоматический подсчет Rails?

Ответы [ 2 ]

1 голос
/ 03 декабря 2009

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

class Chapter
  belongs_to :script, :counter_cache => true
end

Будет автоматически обновлять @ script.chapter_count перед созданием и после уничтожения всех связанных глав.

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

N.B .: Предполагается, что вы также хотите сохранить счетчик абзацев в главе.

Начните с применения той же теории к модели главы и столбца количества абзацев в таблице сценариев.

class PrepareForCounterCache < ActiveRecord::Migration
  def self.up
    add_column :scripts, :paragraphs_count, :integer, :default => 0
    add_column :chapters, :paragraphs_count, :integer, :default => 0

    Chapter.reset_column_information
    Script.reset_column_information

    Chapter.find(:all).each do |c|
      paragraphs_count = c.paragraphs.length
      Chapter.update_counters c.id, :paragraphs_count => paragraphs_count
      Script.update_counters c.script_id, :paragraphs_count => paragraphs_count
    end
  end
  def self.down
    remove_column :scripts, :paragraphs_count
    remove_column :chapters, :paragraphs_count
  end
end 

Теперь, чтобы установить отношения:

class Script
  has_many: chapters
  has_many: paragraphs, :through => :chapters
end

class Chapter
  has_many: paragraphs
  belongs_to :script, :counter_cache => true
end

class Paragraph
  belongs_to :chapter, :counter_cache => true
end

Осталось только сказать Paragraph обновить счетчики абзацев в сценарии как обратный вызов.

class Paragraph < ActiveRecord::Base
  belongs_to :chapter, :counter_cache => true
  before_save :increment_script_paragraph_count
  after_destroy, :decrement_script_paragraph_count

  protected
  def increment_script_paragraph_count
    Script.update_counters chapter.script_id, :paragaraphs_count => 1
  end
  def decrement_script_paragraph_count
    Script.update_counters chapter.script_id, :paragaraphs_count => -1
  end
end
0 голосов
/ 03 декабря 2009

Быстрый и простой способ без использования кеша сделать:

class Script
  has_many :chapters
  has_many :paragraphs, :through => :chapters
end

script = Script.find(1)
puts script.paragraphs.size #get the count
...