In my effort for porting the geokit-rails plugin to Rails 3, I've found that it would really benefit a full rewrite of the query composition parts.
My work can be followed here : http://github.com/jlecour/geokit-rails/ (make sure to look at the gem branch until it is merged into master) Any help is welcome.
The current version, compatible with Rails 2, has 2 main methods (find
and count
) and some utility methods, that are making some changes to the select/conditions/limit/order/… parts of the options hash passed to ActiveRecord and then call the super
related method on the model's class.
With ActiveRecord 3 and its scope approche, I think we don't need to mess with the hash anymore if we use the power of scopes. I would be cleaner, more chainable and reusable, …
That said, we have to consider the kind of additions Geokit makes to a typical query. As a brief summary, here is how it works.
Any model can be extended to become mappable with the acts_as_mappable
method called in the model definition. It has to have a latitude
and a longitude
column (the name can be changed) and some defaults are set (the formula, the distance unit, …).
To be able to find entries in the database that are, for example, within 10 miles from an origin point (some coordinates, of another entry), we need to add a virtual column in the select part of the query to get a distance value and a condition in the where part of the query to restrict the results. Some utility methods (like closest
, farthest
, …) even need to add some limit to the query.
All this can be done with some scopes, but they need to play well with previous of future scopes in the chain. For example, if we want to get the distances between our results and a point or reference, we need to add the virtual column to the query result. In this case, the select methods can be used like this
select("*, #{distance_formula} AS distance")
But what if we don't want all the other fields, but only the primary key and the distance value ? Maybe it is possible to look for select scopes added before ours and add our distance column to them. For the moment I don't know if it is even possible, but I guess it is. More complicated : if there is another select scope added after our, how will it behave ? Will it reset the whole select SQL clause (that would'nt be good) ?
Another question came up : if a utiliy method (or scope) is adding a limit, is it possible to make it impossible to add another contradictory limit further in the chain ?
Last, but not least, the current version of geokit-rails can be used with associations. That's something I've never really used in my apps, but it is a good feature. I haven't even begun to think about how this can be done with ActiveRecord 3. Maybe it will be very hard, maybe very easy. But at least, I know it'll be something to deal with.
Update : I'm currently reading more ActiveRecord and Arel code, and I've seen that I can access the select clause. I can be done from Arel's low level projections or from AR's higher level select_values. For example :
$ l = Location.select('id, name')
$ l.select_values
# => ['id, name']
The problem is that It can be done only at the instance level, not in a scope definition, at least I've not found how. I'm having some NoMethodError for select_values
@tenderlove Thanks for the tips. I didn't know that select() was cumulative (like order).
I've tried this and it's working, but it's rather strange for the user because :