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
Hey, sorry I'm late to this party. Anyway, what I was basically suggesting was that you might want to take a look at this:
http://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/query_methods.rb#L191
And of course, this:
http://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/query_methods.rb#L240
The latter method, build_select, could be overridden by including a module into ActiveRecord::Relation.
so where it currently says:
... you might rewrite it to say:
Of course, taking a page from what Aaron said above, I may be overthinking this. You should be able to just set up a few scopes on the model and make things happen. I think this way is kinda sexy though.