Ruby on Rails Tuesday, December 3, 2019

Hello,

Lets say that I have a model class like `Car < ActiveRecord::Base` and then, I want to extend it with an abstract class in between a sort of `Car < CacheableActiveRecord::Base < ActiveRecord::Base`

In `CacheableActiveRecord::Base` I'll overwrite methods like `find_by`, `find_by!` and `find` with the intention of checking out Redis/Memcached before calling super and letting Rails resolve this to the underlying db, I'm using Rails 4.2.7.1

By extending `Car` an `after_commit` hook will be created for each instance of the `Car` class, that hook will clear the cached key for this model upon commit, This is to get the effect, of releasing the cache on save.

This is an implementation for my `find` method in `CacheableActiveRecord::Base`

```
    def self.find(*ids)
      expects_array = ids.first.kind_of?(Array)
      return ids.first if expects_array && ids.first.empty?

      ids = ids.flatten.compact.uniq

      case ids.size
      when 0
        super # calling supper will generate an exception at this point
      when 1
        id = ids.first

        result = get_from_cache(id)
        unless result
          result = super # I expect this to get the data from db
          if result
            result = set_to_cache(id, result) 
          end
        end

        expects_array ? [ result ] : result
      else
        super # for now let's just skip on multiple ids
      end
    rescue RangeError
      raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
    end
```

I have tests for this, and they even seem to work. for the implementation of `set_to_cache` and `get_from_cache` I have the following code

```
    def self.get_from_cache(entity_id)
      return nil unless entity_id

      cached = Rc.get!(get_cache_key(entity_id))
      if cached
        puts "cache hit"
      end

      return cached ? Marshal.load(cached) : nil
    end

    def self.set_to_cache(entity_id, entity)
      return nil unless entity && entity_id

      dump = Marshal.dump(entity) 

      Rc.set!(get_cache_key(entity_id), dump)

      return Marshal.load(dump) 
    end
```

My doubts here are:

  • Is `Marshal` safe? can one do this? taking into account that this cache will be shared among instances of the same rails app, running in different servers.
  • Is it better to serialize to json? is it possible to serialize to json and then rebuilt an object that will work as regular active record object? I mean one on which you can call `.where` queries on related objects and so on?
I'm a newbie to Rails and Ruby, started coding with both two weeks ago, my background is mostly java xD (finding Ruby great BY THE WAY hahaha)

Thank you

Daniel


--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/ff0d04b7-0ea8-414e-99a5-3d9f73329091%40googlegroups.com.

No comments:

Post a Comment