Picky Active Record 2 Tweet
This post talks about integrating Picky directly into Rails/ActiveRecord.
(By the way, greetings from Rails Camp X Adelaide – come up and say hi if you are here!)
In the last post we talked about a light active record integration. This has been implemented in the prototype and released in Picky 4.0.9.
By light integration we mean:
- You have a separate Picky server.
- The Picky server is not configured via the ActiveRecord model.
- The ActiveRecord data is simply sent to the Picky server as-is for indexing after each commit.
A quick example of 4.0.9 ActiveRecord integration
First, configure a Sinatra Picky server to be open for external indexing.
class YourSearch < Sinatra::Base extend Sinatra::IndexActions # Configure indexes etc. as usual end
Then, configure your AR model:
class Model < ActiveRecord::Base # These are the default options. # extend Picky::Client::ActiveRecord.configure(host: 'localhost', port: 8080, path: '/') # The model definition as usual. end
And that’s it already :)
While the above is very nice, you still need a separate server.
Usually I advocate keeping search separate from the app, because normally, search and app have different goals. For example, caching for either needs to work differently. Search maybe needs to be restarted independently etc.
But sometimes, you simply want a quick and simple search to directly run in the one server you have.
So instead of setting up a separate server, we would integrate Picky directly in the model.
How would we do this?
A first simple implementation
At this point I am incredibly glad to have designed Picky to work and run anywhere.
Since you already can stick it anywhere (a Sinatra server, a DRb server, a simple script, a PORO, …), you can relatively easily stick it into an active record model.
How, you ask? Let me show you the whole thing and then pick it apart.
class Model < ActiveRecord::Base class << self data = Picky::Index.new :models do category :name category :surname end define_method :replace do |model| data.replace model end define_method :remove do |id| data.remove id end models = Picky::Search.new data define_method :search do |*args| models.search *args end end after_commit do if destroyed? self.class.remove self.id else self.class.replace self end end end
Got that? If not, here’s a step by step explanation:
We want the index and the search object to reside in the (singleton) class to define methods there, so we open it:
class << self
Then we define a Picky index (two searchable categories,
surname) and two methods. One to
replace (“insert or update”) indexed models and one to
remove indexed models with a given id:
data = Picky::Index.new :models do category :name category :surname end define_method :replace do |model| data.replace model end define_method :remove do |id| data.remove id end
Why am I using
define_method instead of
def? I want to capture the
data (index) and the
models (search) in the block for these methods to use them later on.
These two methods, since defined on the class’ singleton class, are used like that:
These are all the methods that have to do with curating the index.
Finally, we want the class to update the index as soon as it changes. We use AR 3.0+
after_commit callback for that:
after_commit do if destroyed? self.class.remove self else self.class.replace self end end
So if the object has been destroyed, we remove it from the index (using the “class methods” we defined earlier). If it hasn’t, we simply replace the data.
Interesting to note: On a
replace, Picky simply calls the methods the categories name:
surname. So not only can Picky index Active Record attributes, but any method it has.
You can already do this in the current Picky version 4.0.9.
However, this has a few disadvantages:
- The indexes aren’t yet saved. (Hint:
- If they would be saved, they would not yet be reloaded.
How do we do this? The dumping is relatively easy, but how do we get the data back into that index when restarting and loading the index? If you’re into trying to implement that have a go. If not, stay tuned! :)
Another question for you: Is sticking the method on the
actually a good idea? What if, say Thinking Sphinx, reloads your models? Is your model – being an AR model – not already doing enough? What about the single responsibility principle?
It’s already night here at Rails Camp X Adelaide, so good night. And good luck. Stay tuned!Next Picky Active Record 3
Previous Picky Active Record