ruby on rails - هيكلة التطبيق القضبان لالتخزين المؤقت الروسي دمية مع وجود علاقة has_many




ruby-on-rails caching (2)

إحدى الطرق التي تعثرت عليها هي التعامل مع هذا عبر مفاتيح ذاكرة التخزين المؤقت. أضف علاقة has_many_through للمعلقين على المقالة:

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

ثم في المقالة / show ، سننشئ مفتاح ذاكرة التخزين المؤقت كما يلي:

<% cache [@article, @article.commenters, @article.author] do %>
  <h2><%= @article.title %></h2>
  <p>Posted By: <%= @article.author.name %></p>
  <p><%= @article.body %></p>
  <ul><%= render @article.comments %></ul>
<% end %>

تكمن الحيلة في أن مفتاح التخزين المؤقت الذي يتم إنشاؤه من رابطة commenters سيتغير كلما تمت إضافة تعليق أو حذفه أو تحديثه. في حين أن هذا يتطلب استعلامات SQL إضافية لتوليد مفتاح ذاكرة التخزين المؤقت ، فإنه يلعب بشكل جيد مع التخزين المؤقت مستوى منخفض Rails وإضافة شيء مثل الأحجار الكريمة identity_cache يمكن أن تساعد بسهولة في ذلك.

أود أن أرى ما إذا كان لدى الآخرين حلول أنظف لذلك.

بعد دراسة مقالات DHH وغيرها من المدونات حول انتهاء صلاحية ذاكرة التخزين المؤقت وملف تخزين الدم الروسي المؤقت ، ما زلت غير متأكد من كيفية التعامل مع نوع واحد من العلاقات. أن تكون محددة ، وعلاقة has_many .

سوف أشارك نتائج بحثي على تطبيق عينة. إنه قليل من رواية القصص ، لذا تابع. لنفترض أن لدينا نماذج ActiveRecord التالية. كل ما يهمنا هو التغيير المناسب في cache_key الخاص 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

لدينا بالفعل مقال واحد ، مع تعليق واحد. كلا من قبل مؤلف مختلف. الهدف هو إجراء تغيير في 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 على Author ، لكن has_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"

في حين أن هذا لا يعمل. وله تأثير كبير في الأداء ، عن طريق تحميل وتحديث وتحديث كل المقالات والتعليق عليها من جانب واحد آخر . لا أعتقد أنه حل مناسب ، ولكن ما هو؟

من المؤكد أن 37 إشارة تستخدم الحالة / المثال قد يكون مختلفًا: project -> todolist -> todo . لكن أتخيل بندًا منفردًا ينتمي أيضًا إلى مستخدم.

كيف يمكن حل مشكلة التخزين المؤقت هذه؟


كما نصحت هنا 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 كاسم العمود وكانت الدلالات "عندما قام المستخدم آخر تعديله". لذلك بسبب اختلاف الدلالات ، لا يمكننا استخدام :touch خيار :touch من خارج منطقة الجزاء. كان لي أن monkeypatch cache_key وطرق مثل هذا https://gist.github.com/tispratik/9276110 وذلك لتخزين الطابع الزمني المحدث في memcached بدلا من عمود updated_at قواعد البيانات.

لاحظ أيضًا أنه يتعذر علي استخدام cache_timestamp_format الافتراضي من Rails كما هو متوفر مع الطوابع الزمنية التي تصل cache_timestamp_format إلى ثوانٍ فقط. شعرت بالحاجة إلى وجود طابع زمني أكثر حبيبية لذا اخترت: nsec (nanoseconds).

الطابع الزمني مع cache_timestamp_format: 20140227181414
الطابع الزمني مع nsec: 20140227181414671756000