mike2r <
mr...@kalanitech.com> schrieb:
> A couple of responses. First, in Rails 4 this was changed. It now
> incorporates generational caching. The cache key has a digest which is a
> hash of the underlying template content so that any changes in content
> will
> bust the cache automatically. Observers have actually been removed from
> Rails 4 although you can still get the functionality back by using a gem.
Actually, that is what I've switched to now. At first, my concern was with
piling up a lot of stale and unused content in the cache. But I did fix that
by switching over to memcached as the cache because it can be limited by
size and has a LRU replacement policy.
To make use of this with fragment caching, I've started to change the cache
keys in a way to ensure that they always include the object change time but
also additional meta data that has to be used to detect cache invalidations
- like adding change times of associated objects or ids of parent objects.
When used together with russian doll caching, this works very well now - and
giving up on using file based caching, performance improved a lot without
borthering about infinite cache growth.
> Second, the architecture did make sense initially. In your typical Rails
> app, you don't want your database updated without going through the
> controller. Even interfaces from other applications are, ideally,
> processed through an API as json or xml. Caching is the least of the
> issues, you want to insure that all the constraints and security
> established in the controller and model are applied. Fragment caching is
> actually a view process and, in MVS, you don't want to manage view
> processes from the model, the controller is designed to be the one to
> generate messages from one to the other. Therefore, you used to generally
> have the Controller generate a message to the view when there's a change
> in
> the underlying model that affect it. By the way, there are things other
> than data that can change a view fragment. In particular, a change in
> image file references that get incorporated into the view come to mind.
That is, of course, true. Actually, I really never want to bother with view
components from the model. That's the point of MVC - and even if it looks
like complicating things at a first glance (especially to beginners), it
always results in a much cleaner design (at least if you don't try to
exploit it), and thus in less bugs and easier to read code.
But:
> There are always situations that won't fit into this, although they are
> usually the exception and not the rule. You could have a resource that
> you maintain only for information and gets updated on some periodic basis
> by a
> batch import. In that case, you are correct, you either have to define a
> method within the model (which is most common) that may cross the
> boundaries a bit.
There are situations which do not go through the controller - and cannot.
The controller is being accessed through the action dispatcher. If I do have
a background worker, it won't go that route. It will become a controller
more or less itself which does the job. So, it appears to me that Rails is
missing some glue part between the actual dispatching and the persistence
layer which should not be the ActionController as a sole component.
I've seen some people creating extensions to Rails that fill this gap
(mostly based on events or notifications/subscriptions, an example is wisper
[1]), which actually look clean and like good ideas but still cumbersome to
integrate into Rails, probably just because Rails lacks native and well
integrated support for this. The main idea behind this concept is to insert
a service layer between controllers and models. I like that idea because I
could use the same service layer from background jobs. But I don't think it
would have solved the specific problem I had with invalidating caches. And
after some testing I found programmatically invalidating caches through some
logic is incredibly slow in Rails (defeating to having the purpose of using
caches) when you do huge batched updates to your data. Thus, I decided to go
that memcached route which can do all the heavy lifting for me.
[1]:
https://github.com/krisleech/wisper