This gem allows to save specific attributes in cache and save it to DB after limited time.
class Device < ActiveRecord::Base attr_cached :lat, :lon, by: :last_activity, expires_in: 5.minutes # Override setter (always call _cached method version!) def lat=(s) if s self.lat_cached = s super(s) end end end
This means that parameters lat, lon, last_activity are persisted in Rails.cache. When the Device record is loaded from DB, those parameters are loaded from cache (if last_activity in DB is lower than last_activity in cache)... If you call save on user record and only lat, lon and last_activity parameters were changed, the record will be stored in DB only if last_activity stored in DB are older than 5 minutes!
There is a problem in dirty checking currently open in Rails! rails/rails#21442 Please see the dont reset dirty model after not save test to avoid current issue. We hope it will be fixed in new version of rails.
If you want to store your model data in other specified cache, you can override attr_cached_key method in your model.
class Device attr_cached :lat, :lon def attr_cached_key "device_#{id}" end end
2.1.5 :010 > d = Device.find 1 Device Load (2.2ms) SELECT "devices".* FROM "devices" ORDER BY "devices"."id" DESC LIMIT 1 => #<Device id: 1, user_id: 548, lat: nil, lng: nil, last_activity: nil, created_at: "2015年09月25日 14:24:45", updated_at: "2015年09月28日 15:40:25"> 2.1.5 :012 > d.lng = 10.302 => 10.302 2.1.5 :013 > d.last_activity = Time.zone.now => Mon, 28 Sep 2015 21:01:06 CEST +02:00 2.1.5 :014 > d.save! # This will touch the DB! (0.3ms) BEGIN SQL (3.4ms) UPDATE "devices" SET "last_activity" = 1,ドル "lng" = 2,ドル "updated_at" = 4ドル WHERE "devices"."id" = 1 [["last_activity", "2015年09月28日 19:01:06.955555"], ["lng", 10.203], ["updated_at", "2015年09月28日 19:02:40.173626"]] (0.5ms) COMMIT => true 2.1.5 :015 > d = Device.find 1 Device Load (2.2ms) SELECT "devices".* FROM "devices" ORDER BY "devices"."id" DESC LIMIT 1 => #<Device id: 1, user_id: 548, lat: nil, lng: 10.2013, last_activity: "2015年09月28日 19:01:06.955555", created_at: "2015年09月25日 14:24:45", updated_at: "2015年09月28日 19:02:40.173626"> 2.1.5 :016 > d.lat = 15.203 => 15.203 2.1.5 :017 > d.last_activity = Time.zone.now.advance(seconds: 5) => Mon, 28 Sep 2015 21:04:42 CEST +02:00 2.1.5 :017 > d.save! # This will not! (0.3ms) BEGIN (0.2ms) COMMIT => true 2.1.5 :015 > d = Device.find 1 Device Load (2.2ms) SELECT "devices".* FROM "devices" ORDER BY "devices"."id" DESC LIMIT 1 => #<Device id: 1, user_id: 548, lat: nil, lng: 10.2013, last_activity: "2015年09月28日 19:01:06.955555", created_at: "2015年09月25日 14:24:45", updated_at: "2015年09月28日 19:02:40.173626"> 2.1.5 :016 > d.lat => 15.203 2.1.5 :017 > d.lat = 12.203 => 12.203 2.1.5 :018 > d.last_activity = Time.zone.now.advance(minutes: 10) => Mon, 28 Sep 2015 21:14:42 CEST +02:00 2.1.5 :020 > d.save! # This will (0.3ms) BEGIN SQL (3.4ms) UPDATE "devices" SET "last_activity" = 1,ドル "lng" = 2,ドル "updated_at" = 4ドル WHERE "devices"."id" = 1 [["last_activity", "2015年09月28日 19:14:42.952355"], ["lng", 12.203], ["updated_at", "2015年09月28日 19:10:20.174329"]] (0.5ms) COMMIT => true
If you really want from some reason write record to database and you've changed only cached values, set cache_force_save on object to true.
device = Device.first device.lat = 5 device.cache_force_save = true device.save! # This will update records in database (and each next save on this object too!)
gem 'attr_cached', github: 'netbrick/attr_cached'