How to Disable Rails Content Linking at Runtime

I import records in bulk and do not want to update the counter every time. I want to skip counter_cache sql server updates during bulk upsert, then call reset_counters at the end of the loop.

I tried:

my_model = MyModel.find_or_initialize_by_slug row[:slug] my_model.association(:my_association).reflection.options[:counter_cache] = false my_model.attributes = {:name => "Christopher"} my_model.save! 

but I can see in the sql output that it is still updating counter_cache.

note: I cannot use activerecord-import because I want to execute upserts and I use postgresql

+6
source share
1 answer

You have several different options for skipping the counter cache update, and the one you choose really depends on how you want to structure your application. I will discuss various ways that you can bypass the cache counter, and mention some of the considerations you can make with this.

Basically, there are three different ways to skip updating the cache counter:

Please note that the first two of the above parameters are more related to disabling callbacks in ActiveRecord, and this makes sense because the counting cache is implemented internally using a callback.

When Rails loads a model that has associations with a cache counter, it dynamically defines callback methods. If you want to disable them as a callback, you first need to figure out what the callback names are.

There are two main ways to find out which methods are defined by Rails to implement these callbacks. You can read the Rails source to find out the names that it will generate using the String incorporation, or you can use introspection to find out which methods your class answers. I will give an example of how you can use introspection to find out the callbacks defined by ActiveRecord in order to automatically implement counter caching.

Suppose you have a SpecialReply class that descends from the Reply class that descends from ActiveRecord :: Base ( this example comes from a test suite with Rails ). It has a cache counter column as defined below:

 class SpecialReply < ::Reply belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count' end 

In the console, you can see which methods your class responds to using .methods . This will cause a lot of noise, since each instance of Object already responds to many methods, so you can narrow the list as follows:

 1.9.3-p194 :001 > sr = SpecialReply.new 1.9.3-p194 :002 > sr.methods - Object.methods 

On the second line you're talking about, show me all the methods that my SpecialReply instance responds to, minus those that all objects respond to. This often helps with introspection by filtering out methods that are not of the type of class you are looking at.

Unfortunately, even after this filtering, there is a lot of noise due to the methods that ActiveRecord adds to all its descendant classes. grep is useful in this case - since ActiveRecord helps to create counter callback methods containing String counter_cache ( see Metaprogramming used by ActiveRecord to generate the counter cache method for belongs_to association ), you can recognize callbacks related to counter caches with the following:

 1.9.3-p194 :001 > sr = SpecialReply.new 1.9.3-p194 :002 > sr.methods.map(&:to_s).grep(/counter_cache/) 

Note that since grep runs on String and methods returns Array array names, we first use to_proc ( &: to convert all characters to strings and then output grep out to those containing counter_cache . This leaves me with the following methods, which seem similar to the fact that they were probably automatically generated by ActiveRecord as callbacks to implement counter caching:

 belongs_to_counter_cache_after_create_for_special_topic belongs_to_counter_cache_before_destroy_for_special_topic belongs_to_counter_cache_after_create_for_topic belongs_to_counter_cache_before_destroy_for_topic belongs_to_counter_cache_after_create_for_topic_with_primary_key belongs_to_counter_cache_before_destroy_for_topic_with_primary_key 

You should be able to perform a similar process in your program to determine the method names added by ActiveRecord so that you can knock them out of existing callback removal instructions .

Your choice of the above options depends on the structure of your program and on the compromises that you are ready to consider to increase the efficiency of data loading. It should be noted that the first two options can make your code less readable by changing the behavior of the class from the outside (monkey patch) and can make your system unstable bypassing business rules (updating cache columns) when updating data. For these reasons, I would think about whether you can create another class to load your data in an optimized way, minimizing the impact on readability or data consistency.

+5
source

Source: https://habr.com/ru/post/908646/


All Articles