23

キーベースのキャッシュの有効期限とロシアン ドール キャッシングに関する DHH や他のブログ記事を調べた後でも、1 つのリレーション タイプを処理する方法がわかりません。具体的に言えば、has_many関係。

サンプルアプリでの調査結果を共有します。ちょっとした話ですので、ちょっと待ってください。次の ActiveRecord モデルがあるとします。私たちが気にかけているのは、モデルの を適切に変更することだけcache_keyですよね?

class Article < ActiveRecord::Base
  attr_accessible :author_id, :body, :title
  has_many :comments
  belongs_to :author
end

class Comment < ActiveRecord::Base
  attr_accessible :article_id, :author_id, :body
  belongs_to :author
  belongs_to :article, touch: true
end

class Author < ActiveRecord::Base
 attr_accessible :name
  has_many :articles
  has_many :comments
end

すでに 1 つの記事と 1 つのコメントがあります。どちらも別作者。目標はcache_key、次の場合に記事の を変更することです。

  1. 記事の本文またはタイトルの変更
  2. コメントの本文が変更されます
  3. 記事の著者名の変更
  4. 記事のコメントの作者名が変わります

したがって、デフォルトでは、ケース 1 と 2 に適しています。

1.9.3-p194 :034 > article.cache_key
 => "articles/1-20130412185804"
1.9.3-p194 :035 > article.comments.first.update_attribute('body', 'First Post!')
1.9.3-p194 :038 > article.cache_key
 => "articles/1-20130412185913"

ただし、ケース 3 には当てはまりません。

1.9.3-p194 :040 > article.author.update_attribute('name', 'Adam A.')
1.9.3-p194 :041 > article.cache_key
 => "articles/1-20130412185913"

cache_keyの複合メソッドを定義しましょうArticle

class Article < ActiveRecord::Base
  attr_accessible :author_id, :body, :title
  has_many :comments
  belongs_to :author

  def cache_key
    [super, author.cache_key].join('/')
  end
end

1.9.3-p194 :007 > article.cache_key
 => "articles/1-20130412185913/authors/1-20130412190438"
1.9.3-p194 :008 > article.author.update_attribute('name', 'Adam B.')
1.9.3-p194 :009 > article.cache_key
 => "articles/1-20130412185913/authors/1-20130412190849"

勝つ!しかしもちろん、これはケース 4 では機能しません。

1.9.3-p194 :012 > article.comments.first.author.update_attribute('name', 'Bernard A.')
1.9.3-p194 :013 > article.cache_key
 => "articles/1-20130412185913/authors/1-20130412190849"

では、どのようなオプションが残っていますか?has_many上のアソシエーションを使用して何かを実行できますAuthorhas_many、オプションを使用しません{touch: true}。おそらく理由があります。次の行に沿って多少実装できると思います。

class Author < ActiveRecord::Base
  attr_accessible :name
  has_many :articles
  has_many :comments

  before_save do
    articles.each { |record| record.touch }
    comments.each { |record| record.touch }
  end
end

article.comments.first.author.update_attribute('name', 'Bernard B.')
article.cache_key
  => "articles/1-20130412192036"

これは機能しますが。すべての記事とコメントを1 つずつ読み込み、インスタンス化、更新することで、パフォーマンスに大きな影響を与えます。それが適切な解決策だとは思いませんが、それは何ですか?

確かに 37signals の使用例 / 例は異なる場合があります: project -> todolist -> todo. しかし、1 つの todo アイテムもユーザーに属していると思います。

このキャッシュの問題をどのように解決しますか?

4

2 に答える 2

0

ここでアドバイスされているようにhttps://rails.lighthouseapp.com/projects/8994/tickets/4392-add-touch-option-to-has_many-associations、私の場合、関連するオブジェクトのタイムスタンプを更新するために after_save コールバックを作成しました。

  def touch_line_items_and_tactics
    self.line_item_advertisements.all.map(&:touch)
  end

余談ですが、列名が「ユーザーが最後に変更しlast_modified_timeたとき」というセマンティクスを持つレガシーデータベース上に Rails アプリを構築しました。そのため、セマンティクスが異なるため、そのままではオプションを使用できませんでした。データベースの updated_at 列ではなく memcached に更新されたタイムスタンプを保存するために、 このhttps://gist.github.com/tispratik/9276110のような cache_key および touch メソッドにモンキーパッチを適用する必要がありました。:touch

cache_timestamp_formatまた、タイムスタンプが秒までしか提供されていないため、Railsのデフォルトを使用できなかったことにも注意してください。より詳細なタイムスタンプが必要だと感じたので、:nsec (ナノ秒) を選択しました。

cache_timestamp_format のタイムスタンプ: 20140227181414
nsec のタイムスタンプ: 20140227181414671756000

于 2014-02-28T17:59:30.433 に答える