Are you CALM enough?
Seems like a weird question right? I was taking the subway home and one side of the car was filled with ads saying:
- Are you CALM enough?
- Are you STRONG enough?
- Are you COOL enough?
- Are you CLEAR enough?
What were these adds for? NYS Child Protective Services looking for people to apply. I wanted to add a couple:
- Are you ROBOTIC enough?
- Are you EMOTIONALLY CRIPPLED enough?
because it sounds like they are looking for people with cast-iron stomachs who don’t feel anything. They probably are, that’s what’s sad. Every face on the ads was stoic, mask-like. Made me want to curl up into a ball, not apply for a job.
Bad Bath & Beyond Oddyssey
So I made a trek to BB&B yesterday, on 6th Ave and 18th St. (NYC). I hadn’t been in several years, so my list of things I needed had gotten pretty long. Plus, it is impossible to go in there and not walk out with twice as much as you expected. (As I was standing in line to have my purchases scheduled for delivery, the woman in front of me was saying the same thing to the delivery coordinator, who I’m sure hears that at least once a day.) My goal was to spend less than $1000, and I pulled through with only $850.
I got a humidifier, which I’ve been needing as it just gets dry with my boiler heat in the winter, even though winter is officially over. Nothing worse than itchy skin. I probably could have gotten it on sale in a week or two, oh well.
But the coolest little things I’ve found so far, are these little metal cans with magnetic bottoms, and clear tops that I put my vitamins and a couple of spices in and then stuck to the fridge door, clearing off the Boos prep table of those 4 jars/bottles. Only $2 a pop. And then I got a combined pepper mill/salt shaken, to knock down the number of things on my prep table to just the one.
Also got a coffee maker, as decaf coffee has replaced cigarettes as my vice of choice since I quit smoking. I know, I know, ‘DECAF??!?!?’ I’m sensitive to caffeine in general, so decaf, which still has like 1/6th of the caffeine of regular coffee, gives me a little buzz. Plus I drink a lot. And with my sleep patterns so messed up, half the time I wake up at 2am and have to wait for hours until my local cafe opens, or I wake up at 6pm right after they closed. And the nearest decent coffee is about half a mile away. Not that I don’t need the exercise…
Rails Active Record Lameness
I know this is sacrilegious, but there is some serious lameness going on in ActiveRecord I’ve dealt with lately. Maybe I’m drawing outside of the Rails lines (going off the tracks?), but ActiveRecord seems to go out of its way to make things a pain in the ass.
AR::Base#sanitize_sql being a ‘protected’ method has always been a burr in people’s sides. This means you can’t call it yourself on your own piece of SQL. Presumably it is done this way so people HAVE to do it the Rails way, whether that means duplicating a bunch of code, or taking a lot more time for a one-off project, etc.
Currently I’m working a report generator for Flex, where the Flex app handles the SQL generation and passes back an XML version of the sql options like:
<query>
<name>
</name>
<sql>
<select>
<![CDATA[Date(created_at) as date]]>
</select>
<select>
<![CDATA[count(id) as total]]>
</select>
<from>
</from>
<conditions>
</conditions>
<group>
<![CDATA[date]]>
</group>
<having>
<![CDATA[date >= :start_date and date <= :end_date]]>
</having>
</sql>
</query> Now we can argue all day about the best way to do this, but the reality is that only Admin authenticated people are going to see these reports, so the fact that someone could send arbitrary sql against the database is outweighed by the Flex-ibility of being able to dynamically adjust the query values in Flex without having to create a custom server-side method for each report. It is easier in my case to let more readily available/cheaper Flex programmers handle this than more expensive Ruby coders.
Getting this accomplished in Rails led to 5 workarounds in the code:
def replace_named_bind_variables_no_quotes(statement, bind_vars) #:nodoc:
statement.gsub!(/:(\w+)/) do
match = $1.to_sym
if bind_vars.include?(match)
bind_vars[match]
else
raise ActiveRecord::PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
end
end
end
def query
# from_xml puts it in something like { queries => {query => [{name, sql}, {name,sql}....] }}
queries = Hash.from_xml(params[:queries])['queries']['query']
# logger.dbg queries.inspect
# generate the report structure
report = []
queries.each { |data|
query = data['sql']
logger.dbg query.inspect
# Now we need to get around a bunch of ActiveRecord lameness....
# Presumably it is done this way to satisy someone's idea of 'how you should do things'
# rather than, 'let's help them do it, no matter how they want to get it done'
# first, AR doesn't do bind variables for anything but conditions...
replace_named_bind_variables_no_quotes(query['group'], params) if query['group']
replace_named_bind_variables_no_quotes(query['having'], params) if(query['having'])
# second, we need to join the select clauses, as :select doesn't accept an array...
query['select'] = query['select'].join(', ')
# third, AR doesn't support a separate HAVING clause, you have to attach it to GROUP BY
if query['having'] and query['group'] # you always have both...
query['group'] = query['group'] + " HAVING " + query['having']
query.delete('having')
end
# fourth, we need to intern the keys so that they pass 'inspection' by AR
interned_query = {}
query.each { |key, value|
interned_query[key.intern] = value if(value != nil) # AR doesnt like :conditions => nil either...
}
logger.dbg interned_query.inspect
# fifth, we need to use Creative instead of just ActiveRecord::Base because there is a bug/weirdness in reset_table_name
# where it can't find the abstract_class
report << [data['name'], Creative.find(:all, interned_query)]
}
# output the results xml
str = ''
xml = Builder::XmlMarkup.new(:target => str, :indent => 1)
xml.result {
report.each { |query|
xml.query {
keys = []
xml.name query[0]
xml.cols {
exemplar = query[1].first
exemplar.attributes.each { |key, value|
xml.col key
keys << key
}
}
xml.rows {
query[1].each { |row|
xml.r {
keys.each { |key|
xml.v row.attributes_before_type_cast[key]
}
}
}
}
}
}
}
render :xml => str
end