tablas tabla relaciones rails polimorficas migraciones intermedia comando clase caracteristicas belong association asociaciones active ruby-on-rails ruby caching fragment-caching russian-doll-caching

ruby-on-rails - polimorficas - relaciones de tablas en ruby on rails



Estructurar una aplicación de Rails para el almacenamiento en caché de Muñeca rusa con una relación has_many (2)

Después de estudiar DHH y otros artículos de blog sobre la caducidad del caché basado en claves y el caché ruso de muñecas, todavía no estoy seguro de cómo manejar un tipo de relación. Para ser específico, una relación has_many .

Compartiré los resultados de mi investigación en una aplicación de muestra. Es un poco de contar historias, así que espera. Digamos que tenemos los siguientes modelos de ActiveRecord. Todo lo que nos importa es un cambio adecuado de la cache_key del modelo, ¿verdad?

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

Ya tenemos un artículo, con un comentario. Ambos por un autor diferente. El objetivo es tener un cambio en la cache_key para el artículo en los siguientes casos:

  1. Cambios de cuerpo o título del artículo
  2. Cambios en el cuerpo de su comentario
  3. El nombre del autor del artículo cambia
  4. El nombre del autor del comentario del artículo cambia

Entonces, por defecto, somos buenos para los casos 1 y 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"

Pero no para el caso 3.

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

Definamos un método compuesto cache_key para 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"

¡Ganar! Pero, por supuesto, esto no funciona para el caso 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"

Entonces, ¿qué opciones quedan? Podríamos hacer algo con la asociación has_many en Author , pero has_many no toma la opción {touch: true} , y probablemente por una razón. Supongo que podría implementarse algo a lo largo de las siguientes líneas.

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"

Mientras esto funciona Tiene un gran impacto en el rendimiento al cargar, crear instancias y actualizar cada artículo y comentar por ese otro, uno por uno . No creo que sea una solución adecuada, pero ¿qué es?

Seguro que el caso / ejemplo de uso de 37signals podría ser diferente: project -> todolist -> todo . Pero me imagino que un único artículo pendiente también pertenece a un usuario.

¿Cómo se resolvería este problema de almacenamiento en caché?


Como se recomienda aquí, https://rails.lighthouseapp.com/projects/8994/tickets/4392-add-touch-option-to-has_many-associations , en mi caso, acabo de crear una devolución de llamada after_save para actualizar las marcas de tiempo de los objetos relacionados.

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

Aparte, construimos nuestra aplicación de rieles en una base de datos heredada que tiene last_modified_time como el nombre de la columna y su semántica era "cuando el usuario la modificó por última vez". Entonces, debido a las diferentes semánticas, no pudimos usar la opción :touch de la caja. Tuve que parchear el cache_key y tocar métodos como este https://gist.github.com/tispratik/9276110 para almacenar la marca de tiempo actualizada en memcached en lugar de la columna updated_at de las bases de datos.

También tenga en cuenta que no pude usar el cache_timestamp_format predeterminado de Rails, ya que se proporciona con marcas de tiempo solo hasta segundos. Sentí la necesidad de tener una marca de tiempo más granular, así que elegí: nsec (nanosegundos).

Indicación de fecha y hora con cache_timestamp_format: 20140227181414
Indicación de fecha y hora con nsec: 20140227181414671756000


Un método con el que tropecé sería manejarlo a través de las teclas de caché. Agregue una relación has_many_through para comentaristas al artículo:

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

Luego, en el artículo / show, construiremos la clave de caché de esta manera:

<% 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 %>

El truco es que la clave de caché generada a partir de la asociación de commenters cambiará cada vez que se agregue, elimine o actualice un comentario. Si bien esto requiere consultas SQL adicionales para generar la clave de caché, funciona muy bien con el almacenamiento en caché de bajo nivel de Rails y la adición de algo así como la gema identity_cache puede ayudarlo fácilmente.

Me gustaría ver si otras personas tienen soluciones más claras para esto sin embargo.