Workaround for has_many :through overriding the :select clause
As I mentioned earlier a named_scope select clause will get overridden in a has_many :through.
class Grandparent
has_many :grandchildren, :through => :children
end
class Grandchild
named_scope :summed_ages_by_gender, :select => "SUM(age) as age", :group => :gender
end
Grandparent.first.grandchildren.summed_ages_by_gender
#does not do what you want, because the through overrides the selectIf you have a case where this isn’t acceptable, such when you have a complicated aggregate select that you would like to call on a has_many through, there is an ugly work-around. You can recreate the has_many :through, with joins in a scope on the child model, then return that in a method of the grandparent.
class Grandparent
def grandchildren
Grandchild.grandchildren.scoped({:conditions => ['grandparents.id = ?'], id})
end
end
class Grandchildren
named_scope :summed_ages_by_gender, :select => "SUM(age) as age", :group => :gender
named_scope :grandchildren, :joins => ['JOIN parents ON grandchildren.parent_id => parents.id', 'JOIN grandparents ON parents.grandparents_id = grandparents.id']
end
Grandparent.first.grandchildren.summed_ages_by_gender
#should workObviously I would not advise using this as a relationship model – it was one I just threw together for elucidation. And I haven’t run this exact code, but I have run the code it is a dummied up copy of, with great success.
Maybe I’ll try and come up with a patch to fix the original problem, but the through select logic is probably some of the most edge-case ridden in AR associations, so I am not sure how easy it would be.
Update: I made a ticket with a patch for the failing test, at least.
Another ticket on Rails Metal loading/requiring issues
Our (YieldBuild, Inc) use of metal for one of our two highest throughput actions seems to manage to ferret out edge-cases, as I know have another ticket on Rails Metal requiring issues
This one, thankfully doesn’t have any serious performance hits on production (fixing the other one by manually forcing thin to use the right rails handler via a basic config.ru dropped our load by roughly 30%).
There is just a problem with having a dependency on a project constant from within metal, and you have the choice of having development mode choke on the second metal request (due to Rails having unloaded the constant, but not knowing metal needed it reloaded), or forcing a manual require, which will cause a double require. Hopefully none of your models, etc, are non-idempotent on file load (aside from warnings about redefining constants), right?
Problems with mongrel_cluster and Rails 2.3 dispatcher reloading your metal every request
So, once I added a couple Rails metal to our high volume site, my boss complained that our performance took a serious hit. In tracking it down (with strace) we realized that every request was re-requiring each metal, which involves a full load path search. This was not happening on our local script/server started mongrels, but was happening on production for both thin and mongrel_cluster, even after we had gone through every setting and made them match exactly.
We traced it down to the difference of mongrel_cluster versus the script/server. Script/server is going to use the built in, updated for Rails 2.3, mongrel handler. The old stuff called by thin or mongrels started by mongrel_cluster, is going to use the old (“deprecated”) dispatch path, which in a cgi-ish fashion rebuilds the dispatcher and all rack middleware and metal each time, which means re-requiring them all.
So now I am not sure what to do. Do we have to start all of our mongrels with rackup? Do we take the rack mongrel handlers from rails and patch them into wherever? Do I file a bug for Rails that there at least needs to be some documentation, other than just deprecating the method that a stock mongrel will call?
Update I made a ticket for it Also having mongrel start up using the handler in the rails vendorized rack as a config will fix the problem for mongrel. I’m not sure about thin, as that handler seems to be rackup specific?
Update2 Ezra said he’d go with rackup and gave me a monit script for it
Update3 We made a barebone rails config.ru and made thin use that, forcing it down the path of using the built-in rails handler. That dropped our load by 30% roughly, so yeah, this behavior had a significant impact on us.
Follow-up on the iPhone theft +1 for Amex and SFPD
Getting insurance money from American Express for the theft of my iPhone was straight-forward. It is only the purchases price ($299 + tax), not the replacement value, but that is better than nothing.
Also an Inspector from the San Francisco Police Department just called me to record an electronic statement. Apparently they got good enough video from the muni cameras to make a bulletin from, so they want my statement on hand for a follow-up if someone identifies suspects. I have to say, throughout this SFPD has been friendly, responsive, and more pro-active than I expected. I wonder if that is at all affected by me being a well-off, educated, white, male? All I know is they seemed far more interested in this than SLC PD where for a car theft, and a couple break-ins, I had. Maybe the involvement of a gun make a difference.
Difference between rspec style spec names and test unit? Three lines.
A discussion I overheard in irc made me wonder what possibilities would be opened up if instead of naming tests by convention (test_)all publicly accessible methods were run as tests. This lead down a path to this thought:
class RspecInTU
class << self
alias it define_method
end
it "should say hello" do
puts "hello"
end
end
RspecInTU.new.send "should say hello"
Technomancy told me that it’s easy to actually get miniunit to use all public methods as test methods and came up with a minimum working base
Of course, I wondered if Shoulda already did something like that, and some people confirmed that it does. It’s still neat.
named_scope :select clause gets overridden by a :source specified in a has_many association
FYI. If that wasn’t Greek to you, then that’s about all there is to it.
Correction any :through overrides the :select, not just one specifically :source’d
On iPhone theft and chasing down an armed robber
Sorry for the stream of consciousness, lack of paragraphs, but I am still wired on adrenaline.
Those of you with my phone number, it won’t be good for a little bit. My phone just got snagged out of my hand on the bus. The guy doing the snatch and grab, ran out of the bus as he grabbed it, while his fat compatriot tailed behind him running interference. I kicked off my shoes as I chased after the guy with the phone and weaved around the fat guy out into the street and around the corner after my phone. I pushed the robber up against the chain link fence as I caught up to him, and his gun fell out of his pants. His fat buddy, behind me a little said something to the effect of “what the fuck are you doing” while he said “I didn’t grab it, it fell.” Thinking he meant he missed the grab I let him go as he fumbled for the gun (stupid, I know, but I didn’t know what else to do with him, what try and beat the snot out of the two of them, that’d be assault. And the gun hadn’t registered yet, or had just barely started falling) and went back to look for my phone. Of course, it wasn’t there because the robber had it.
The bus driver called it in to the cops, who took all my info and witness account and gave me a drive home. They are hoping to get something good off the cameras on the bus, and I have a case number. I am canceling all the passwords of things that might be saved on my phone, and already canceled service to it.
update
I just realized when he said “I didn’t grab it, it just fell” he was referring to his gun, to let me know he was not pulling it on me. That makes it somehow more real and scary to accept that he could have been.
Problems with arity when converting a method to a block/proc that accepts an array param
Some consider this hacky, but while working on cleaning up test_benchmark I wanted to pass a named method as a block to a map. In the simplest case you just grab a method reference via object.method(:method_name) and to_proc it with an ampersand. In this case the method definition is basically just a way to store a proc, and this could be replaced by just storing a proc in an instance variable. But it works, both with the method called directly, and passed as a proc/block:
benchmarks = [["a slow test",2.0],["a fast test",0.001]]
def by_time(a,b)
b[1] <=> a[1]
end
benchmarks.sort { |a,b| by_time(a,b) } #works
benchmarks.sort(&method(:by_time)) #works
I discovered you can have problems with arity, though, if the block method is passed an array, which is then expanded out to array.length params, giving you an ArgumentError. For instance, if I am again working with doubles for my benchmark rows:
benchmarks = [["a slow test",2.0],["a fast test",0.001]]
def format_row(tuple)
("%0.3f" % tuple[1]) + " #{tuple[0]}"
end
benchmarks.map { |tuple| format_row(tuple } #works
benchmarks.map(&method(:format_row))
# ArgumentError: wrong number of arguments (2 for 1)
Thanks to Evan Phoenix for pointing out I just need to use a glob param in my method. This won’t work with the direct call anymore, as the tuple gets wrapped in another array by the globbing:
benchmarks = [["a slow test",2.0],["a fast test",0.001]]
def format_row(*tuple)
("%0.3f" % tuple[1]) + " #{tuple[0]}"
end
benchmarks.map(&method(:format_row)) #works
benchmarks.map { |tuple| format_row(tuple }
#Blows up on an invalid index access, because tuple inside format_row is now [["a slow test",2.0]] for the first call
To work around this, in this case, it works to just flatten the array.
def format_row(*tuple)
tuple.flatten!
("%0.3f" % tuple[1]) + " #{tuple[0]}"
end
benchmarks.map(&method(:format_row)) #works
benchmarks.map { |tuple| format_row(tuple } #works
I guess the general conclusion to go with, is be careful doing tricky things like using method references as procs. Especially keep a careful eye on the method signature and how arrays can mess with your arity.
A revamped plugin/gem for benchmarking your ruby/rails test::units
and what I learned about hacking on Test::Unit.
For quite a while I’ve been using Geoffrey Grosenbach’s test_benchmark to see what tests were most egregiously slowing down whole test suites. I (and he as well, actually) was quite dissatisfied with its approach of spamming the console with the full output after each file completed running, as it made the plugin unusable for just keeping enabled. Unfortunately, how to hack test/unit best wasn’t immediately apparent the last time I looked into.
This time I’ve figured it out: I’ve now reworked the plugin so that it waits until all the tests are done running, and then outputs the slowest 10, while dumping the full list to the log (if you are in Rails, or Loggable is otherwise defined). Other info and options can be found at the new github home of test_benchmark.
The original version just redefined Test::Unit::TestSuite#run to wrap it with some benchmarking output.
#code trimmed down to functional base
class Test::Unit::TestSuite
def run(result, &progress_block)
@tests.each do |test|
test.run(result, &progress_block)
#code to store benchmark times here
end
#code to output benchmark times here
end
end
The problem with this is the slightly confusing definition of TestSuite within test/unit (or at least how it ends up working the reality of most projects testing setup). I (and perhaps Geoffrey too) assumed the usual project wide definition of a ‘test suite’ being the entire collection of tests. As I was putting output statements through the codebase, I noticed that each individual test file was being treated as a separate TestSuite, despite inheriting from TestCase. So that meant each time a file completed, the benchmarking code at the end of TestSuite#run spammed the console.
Perhaps there is a way to better organize your tests into Suites, so that this doesn’t happen, but that is moot, because this is how pretty much all projects are organized in reality. As such, I needed to rework the test_benchmark codebase to handle this better.
Instead I used Test::Unit::UI::Console::TestRunner (which is instantiated when you runs test from the console, shockingly enough), which already uses the hooks for individual test, as well as entire rest run, start and stop. I just added a bit more functionality to these functions and BAM, easy-peasy benchmarking that only outputs when the full test run is done.
alias started_old started
def started(result)
started_old(result)
@benchmark_times = {}
end
alias finished_old finished
def finished(elapsed_time)
finished_old(elapsed_time)
benchmarks = @benchmark_times.sort{|a, b| b[1] <=> a[1]}
output_benchmarks(benchmarks)
end
alias test_started_old test_started
def test_started(name)
test_started_old(name)
@benchmark_times[name] = Time.now
end
alias test_finished_old test_finished
def test_finished(name)
test_finished_old(name)
@benchmark_times[name] = Time.now - @benchmark_times[name]
end
Determining where in the inheritance chain a method is defined
Define in your .irbrc.
def Object.method_defined_where(method)
self.ancestors.detect { |a| a.methods(false).include?(method.to_s) }
end
#Usage
#File.method_defined_where('read')
#=> IO
jbarnette and bougyman in #caboose helped me get it closer to actually working. It still probably needs some tuning. Feel free to fork and tweak the gist on method_defined_where, and then comment here.