Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Let's preface this with it's not the answer you are looking for...</p> <p>Now, with that out of the way, here is what I tried and how it relates to the two links I posted in the comments of the question.</p> <pre><code>class User &lt; ActiveRecord::Base # self-referential association - more on this later belongs_to :myself, class_name: "User", foreign_key: :id scope :w_computed_metric, -&gt;() { select{[id, (id *2).as(computed_metric)]} } scope :w_age_in_seconds, -&gt;() { select{[id, (extract('epoch from now()') - extract('epoch from users.created_at')).as(age_in_seconds)]} } scope :w_default_attributes, -&gt;() { select{`*`} } def self.compound_metric scope = User.w_default_attributes.select{(b.age_in_seconds / a.computed_metric).as(compound_metric)} scope = scope.joins{"inner join (" + User.w_computed_metric.to_sql + ") as a on a.id = users.id"} scope = scope.joins{"inner join (" + User.w_age_in_seconds.to_sql + ") as b on b.id = users.id"} end sifter :sift_computed_metric do (id * 2).as(computed_metric) end sifter :sift_age_in_seconds do (extract(`epoch from now()`) - extract(`epoch from users.created_at`)).as(age_in_seconds) end def self.using_sifters_in_select User.w_default_attributes.joins{myself}.select{[(myself.sift :sift_computed_metric), (myself.sift :sift_age_in_seconds)]} end def self.using_from scope = User.w_default_attributes scope = scope.select{[(age_in_seconds / computed_metric).as(compound_metric)]} scope = scope.from{User.w_computed_metric.w_age_in_seconds} end end </code></pre> <p>So, running <code>User.compound_metric</code> in console will yield the results you are looking for - a <code>User</code> object with the additional attributes: <code>computed_metric</code>, <code>age_in_seconds</code>, and <code>compound_metric</code>. Unfortunately, this violates the third constraint you placed on an acceptable answer. Oh well...</p> <p>I also tried a few other things (as you can see from above):</p> <p>First point of note is the self-referential association, which I'm quite proud of - even though it doesn't get us to where we want to go.</p> <pre><code>belongs_to :myself, class_name: "User", foreign_key: :id </code></pre> <p>This nifty piece of code lets you access the same object through a join. Why is this important? Well, Squeel will only allow you to access associations through the <code>joins{}</code> method unless you pass it a string of SQL. This lets us use the <code>sifter</code>s feature of Squeel - in this case not to filter the results, rather to include <em>aggregate</em> columns from the db and let Squeel do the heavy lifting of aliasing and joining the statements. You can test it with the</p> <pre><code>def self.using_sifters_in_select User.w_default_attributes.joins{myself}.select{[(myself.sift :sift_computed_metric), (myself.sift :sift_age_in_seconds)]} end </code></pre> <p>The beauty of sifters to acheive this is the chainability and syntatic sugar - it is very flat and readable.</p> <p>The last bit I tried playing with is <code>.from{}</code>. Before this question, I didn't even know it existed. I was soooo excited with the possibility that I had missed something so simple as including a source for a query (in this case a sub-select). Testing with using_from</p> <pre><code>def self.using_from scope = User.w_default_attributes scope = scope.select{[(age_in_seconds / computed_metric).as(compound_metric)]} scope = scope.from{User.w_computed_metric.w_age_in_seconds} end </code></pre> <p>results in a TypeError:</p> <pre><code>TypeError: Cannot visit Arel::SelectManager from /home/prg10itd/projects/arel/lib/arel/visitors/visitor.rb:28:in `rescue in visit' from /home/prg10itd/projects/arel/lib/arel/visitors/visitor.rb:19:in `visit' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:348:in `visit_Arel_Nodes_JoinSource' from /home/prg10itd/projects/arel/lib/arel/visitors/visitor.rb:21:in `visit' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:139:in `visit_Arel_Nodes_SelectCore' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:121:in `block in visit_Arel_Nodes_SelectStatement' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:121:in `map' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:121:in `visit_Arel_Nodes_SelectStatement' from /home/prg10itd/projects/arel/lib/arel/visitors/visitor.rb:21:in `visit' from /home/prg10itd/projects/arel/lib/arel/visitors/visitor.rb:5:in `accept' from /home/prg10itd/projects/arel/lib/arel/visitors/to_sql.rb:19:in `accept' </code></pre> <p>(and yes, I'm testing against a local copy of the Arel and Squeel). I'm not familiar enough with the internal workings of Arel to resolve the issue without further effort (and most likely a fork of Arel). It does appear that Squeel just passes the <code>from{}</code> method to the Arel <code>from()</code> method without doing anything (beyond the rest of the magic that is Squeel).</p> <p>So where does that leave us? A solution that works, but is not as nice and elegant as I wish it was - but maybe someone else can leverage this to a better solution.</p> <p>PS - this is with Rails v3.2.13 and the respective version of Arel. The source for Rails v4 and Arel are quite different and not tested for this.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload