While working on my upcoming BigAuthor project, I came upon an interesting challenge that turned out to be so simple with MongoMapper that I just have to share it here. Need to create a hash of multiple filter parameters on a MongoMapper document using a form that is cleanly resource-based, using InheritedResources? It’s not as difficult as you might think…
In my MongoMapper::Document model, I have the following keys:
key :filters, Hash, :index => true
Now, I’m expecting to stick a Hash into ‘filters’ in the form:
'people' => ['joe','mary'],
'tags' => 'dog cat vampire zombie'}
So, the idea is, the object that is saved with the above filters Hash provides a context for searching through another collection of objects (let’s call it OtherThings) using the filters. (think email rules in Outlook). Anyway, don’t worry too much about that. It’ll become more clear once I launch BigAuthor in a few weeks or so.
Using InheritedResources + Formtastic gives you a big advantage in creating resourceful controllers and their associated semantic forms really, really quickly.
The controller:
respond_to :html, :xml
end
Seriously. It’s that empty.
The ‘new’ form page (in HAML, of course):
- semantic_form_for @things do |form|
- form.inputs do
= form.input :title
- form.semantic_fields_for :filters do |sub|
- sub.inputs do
= sub.input :tags
= sub.input :colors, :collection => Thing::COLORS, :as => :check_boxes
= sub.input :people, :collection => People.for_filters, :as => :check_boxes
- form.buttons do
= form.commit_button :label => "Create Thing"
Again, that’s it. Really. The checkboxes that are checked get put into Arrays within a params['thing']['filters'] Hash and persist naturally to MongoDB through MongoMapper. No extra work needed.
In fact, the only extra thing I did was to write a short override into the create/update methods so that it strips the blanks from the internal filter arrays. (formtastic’s checkboxes post an empty string for every checkbox that is not checked, which in this case wasn’t what I wanted, but it might be fine or even required for your purposes)
BONUS!
Using Sunspot and Solr for your search solution in your MongoMapper app? Here’s a sample of the search method that my OtherThing class has for creating a search result set based on the filters:
Sunspot.search(self) do
keywords filters['tags']
with(:color).any_of filters['colors']
with(:people).any_of filters['people']
order_by :created_at, :desc
end
end
Exactly how my Sunspot/Solr is setup, I’ll leave for the reader to imagine, but don’t overthink it… it’s not complicated and the above works fast… really, really fast. So fast, that instead of pre-creating and caching the results sets, I just re-generate them on the fly, thereby ensuring they’re always up-to-the-second with the latest OtherThings that have been added to the database.
Once again, Mongo and MongoMapper blows me away with its simplicity, further supported by the brilliant inherited_resources and formtastic!
i done all config as in ur post
it dose
rake ts:config
but error for
rake ts:start
Failed to start searchd daemon. Check log/searchd.log.
Failed to start searchd daemon. Check log/searchd.log
rake ts:in
FATAL: no indexes found in config file ‘config/development.sphinx.conf’
what should be the mistake
Hi, for what it’s worth, Formtastic does the same as the basic Rails helpers when it comes to unchecked checkboxes.
Yeah, that’s true. Good point. Frankly, I usually want that functionality, because in most cases it’s important for working with a relational database to map 1-to-1 even with the ‘not checked’ boxes. In the case of jamming a Hash directly into Mongo, however, my usage just wants a hash with only the things that were checked, since I’m just going to check the whole hash right into the database as-is. It’s an interesting difference, since Rails (and its helpers) were clearly geared towards relational databases. One of those odd things about going the NoSQL route, eh?