In no particular order

reflections, observations, politics, and technology

Jan 16

12 Argument-Enders That Nobody Will Ever Agree With

So I recently came across a posting entitled “12 Argument-Enders That Liberals Will Never Disagree With.” It was a tongue-in-cheek list of things that a conservative, or perhaps libertarian, might say to get out a conversation with someone with whom they disagreed. The underlying point, of course, is that liberals are so misguided that conversation with them can’t be productive, and so simply excusing yourself is a better use of your time.

I personally believe that it’s important to try to understand the viewpoint of people with whom you disagree; it’s the best way to learn. So, in that spirit, I offer the following amendments/corrections to the original that might better inform a conservative (or perhaps libertarian) of the underlying message being sent.

You’re all welcome.

So, you are a conservative (or perhaps libertarian). When you say…

1. THINGS ARE INDEED BROKEN IN DC/SACRAMENTO/(INSERT STATE CAPITAL)!

What they hear: I am pretty comfortable; these things don’t really matter to me. If it were not for the obstructionist Republicans, our grand vision would be implemented and America would be saved

What you mean: Big government cronyism is a huge political problem.

2. I SUPPORT FAIRNESS IN TAXATION!

What they hear: The rich should pay more because they can afford it. 

What you mean: I’m not very good at math. Some people don’t pay nearly enough while a minority pays a disproportionate amount. The whole system – all 73,000 pages of tax codes – needs to be reevaluated.

3. POLITICIANS SHOULD NOT USE PUBLIC ENTITIES FOR PRIVATE PURPOSES!

What they hear: George Washington Bridge and the Internal Revenue Service

What you mean: I don’t care if they’re real scandals or fake ones, the scandals that matter are the ones that make Democrats look bad.  Internal Revenue Service.

4. I SUPPORT RACE AND GENDER EQUALITY!

What they hear: Women and minorities have historically been screwed and so special programs are needed to right these wrongs. 

What you mean: I’m a white male. If all people are equal, then everyone can make it in a free country without paternalistic programs. Let’s try to make the rules equal for all individuals.

5. EVERYONE DESERVES HEALTHCARE!

What they hear: DC-forced, taxpayer subsidized, centrally planned healthcare for all. 

What you mean: I don’t understand that there are limits to the power of market competition. Everyone should be able to purchase whatever health insurance they like, or just to buy health care with cash when they need it. Let’s make healthcare as affordable as possible through open competition and taking the overhead out of it as much as humanly possible.

6. I DEFINITELY BELIEVE IN CLIMATE CHANGE!

What they hear: Man’s activities have disrupted the climate and since market competition does not account for or value externalities, governmental efforts to limit fossil fuels through regulation is, redistribute wealth, and regulate activities are required.

What you mean: I don’t really understand science. Or economics.  Climatechanges – always has, always will. Seeking to regulate the earth’s climate is just an excuse for a government takeover for energy, a pretense for social engineering, and practically impossible.

7. BARACK OBAMA IS AN INSPIRING LEADER!

What they hear:  I am an uncritical fanatic! Everything he does is good and right.

What you mean: I don’t understand the nature of compromise. Continued support of Obama is proof positive of people’s unwillingness to change their minds about a political candidate who has not delivered on his false promises.

8. GEORGE W. BUSH WAS NOT A GREAT PRESIDENT!

What they hear: George W. Bush was a catastrophe. Everything Barack Obama has not been able to fix was his fault.

What you mean: George W. Bush became wildly unpopular! He was the second-most profligate spender in history.

9. I BELIEVE IN PEACE!

What they hear: Peace is the goal. absence of opposition to the left’s agenda.

What you mean: I am terrified of people I don’t know, and I think it’s ok to kill them if they inconvenience me. Our leaders should keep America safe by any means possible, even if it means going to war like we have throughout history.

10. THE COUNTRY IS CERTAINLY GOING IN THE WRONG DIRECTION!

What they hear: I don’t understand the nature of compromise. If only the political class had unfettered rule, we’d all be better off.

What you mean: I don’t believe in compromise. Central planning for a vast and varied populace is impossible and historically ignorant of its track record of massive failure.

11. BARACK OBAMA/KATHLEEN SEBELIUS/ERIC HOLDER/HILLARY CLINTON/HARRY REID/NANCY PELOSI (AND ON) ARE VERY SMART!

What they hear: I think you are very dumb.  I trust these folks to take care of me.

What you mean: I think you are very dumb. These people really know how to game the system for the benefit of elites like themselves and I want them to leave us alone.

12. THE ECONOMY IS DEFINITELY IMPROVING!

What they hear: There is real evidence that demand-side economics works. The Obama administration’s efforts are working.

What you mean:  Even though George W. Bush became unpopular, I can’t stop believing in supply-side economics.  There’s a deal of ruin in a nation, and the American people have resolve to make it past this dreadful presidency.

If you want to have good relations with a liberal conservative (or libertarian), just DO NOT, under any circumstances, even BEGIN to tell them what you mean… expect them to listen to reason.


May 9
“You don’t become great by trying to be great. You become great by wanting to do something, and then doing it so hard that you become great in the process.” Randall Munroe (xkcd)

Apr 7
“The spread of the decimal system to supplant Roman numerals was hindered by language, distance, and ignorance, [until] a man living in Baghdad named “Al Khwarizmi” wrote an Arabic textbook that laid out the basic methods for adding, multiplying, and dividing numbers—even extracting square roots and calculating digits of π. These procedures were precise, unambiguous, mechanical, efficient, correct—in short, they were algorithms, a term coined to honor the author after the decimal system was finally adopted in Europe, many centuries later.” "Algorithms" (S. Dasgupta, C.H. Papdimitriou, and U.V. Vazirani)

Mar 31

On explicit typing

…or, how to offend most of the developers I know in a couple dozen paragraphs.

I have and will never been a fan of strictly type checked languages. They are too fussy; I’ve spent too much time trying to wrestle the type system into submission. Types, to put it plainly, are too often a pain in the ass.

I was reading yet another book on Ruby (well, what do you do for fun?), and came across this comment:

…since there’s no types, it’s really important to do more testing…

This coalesced something that I’ve been struggling to articulate for a long time. I’m equally mystified by people who dismiss typing as unnecessary (which I gather includes essentially the entire Ruby engineering population) and by people who insist that ubiquitous typing is essential to a properly functioning system (you know who you are). And here it is:

Types are testing.

By “types” I mean the whole bag of compile-time tricks, including required object declarations, explicit typing, declared interfaces for objects, etc. In each case the intent is to ensure that things actually take the form we expect them to take when they are passed around.

When you declare something should be a specific type, you are in essence asking the language environment to verify that the code is being used correctly. Obviously that is a form of testing, and if there’s one thing the last decade has brought to our attention, it’s that Testing is Good.

Types are documentation.

Which of these function signatures do you find more self-explanatory?

Ruby:

def complete?(config) { ... }

Hmm. Well, the “?” convention tells us it’s probably a boolean method, and we can guess that there’s some sort of configuration involved. Not a lot of information to go on, actually.

Java:

public boolean is_complete(RequestConfiguration config) throws IOException { ... }

I don’t even have to look at the implementation to have some idea of what’s going to happen there: we’re doing some sort of analysis of request processing, presumably a network request of some kind. If I need information about the config parameter, I can go look at the RequestConfiguration class. Furthermore I know that I have to be ready to handle exceptions. There’s quite a lot of information conveyed by those extra characters. But those characters aren’t free; I’ve more or less tripled the amount of typing I have to do to create the function, and a lot of that has to be replicated carefully and completely over and over and over. Further, much of that information can sometimes be inferred from context, and where not possible, documented in a comment.

Typing should be possible.

Given the above code, let’s say I were to attempt the following Ruby:

obj.complete?({:some => 'hash value'})

We know from our Java example that the complete? method is in fact expecting an object of type RequestConfiguration; but in Ruby we won’t find out about that until run-time, and — since the definition of variables in practice often happens far from their use — figuring out where it happened, and what was expected, and so on, can be time consuming.

Wouldn’t it be neat if we could do that before we tried to use the code? Since Ruby is an interpreted language, there is no such thing as ‘compile time.’ But what if there were a way to run a test that did some level of verification that the things we were calling were getting the types of things they expect?

The Purists of the Cult of Ruby typically respond to the idea of “types” with pitchforks and torches. But they have quietly adopted a quasi-vocabulary for typing: they call it “duck typing.” See, if it quacks like a duck, it’s a duck — but whatever you do, do not suggest that is the same thing as typing. “Duck-typing” isn’t “types.” Um, ok. In Java, that very same idea is called an “interface”, and you can explicitly state that you want to operate on something that implements exactly that signature. People who like Java are often pretty enthusiastic about that stuff…

In my mind the only thing that really changes when you build a type system into a language is how thorough the consistency checking can be… and when that testing happens.

Typing should be optional.

In compiled languages, there is a very natural time to apply testing: when you compile the code. But since typing can be enforced at compile time, systems which allow it almost always insist on it. Have you ever suggested to a Purist of the Cult of Java that types can sometimes get in the way? Their reaction almost always includes lots of words and some color in the face.

Hmm.

If types are testing, and type enforcement is always good, doesn’t that imply that all testing is always good?

Let’s do a little thought experiment. Imagine with me, for a moment, a language which has a built in code-coverage detector which will not allow code to run unless every branch of the code is covered by tests and passes. That’s right, to run your system you have to have implemented 100% code coverage. Some of you, O imagined readers, are nodding your head right now; good idea, huh? You would know that your system would work, when you get it into production. That’s awesome!

I doubt it. The inevitable consequence of this would be a proliferation of tests that exercise code but do not actually care about the result, to the tune of object.do_something() ; assert true. Deadlines happen; if you can’t commit code without test coverage, smart clever people would figure out how to work around the artificial constraint that the language is imposing. More to the point, many skilled, professional developers sometimes opt not to test all their code even if there is no deadline pressure. Some code is simply not important enough to warrant the overhead of a full test suite.

Now we turn to the Purists of Test Driven Development, who will rant about studies showing that TDD slows development but saves a lot of money. Indeed, the evidence is mounting that code with a well designed and thorough test suite will cost less to maintain in the long term than code without. I don’t want to dismiss that finding; it’s very significant, and I wish more developers (and their managers) were aware of it. But it is important only if the code in question will ever actually require support! A lot of code does not: dirt simple code, experimental code, one-off scripts, etc. So our imaginary language would probably need a simple way to indicate “don’t bother testing this section of code” — which really isn’t much different than what we have today, with test engines that report code coverage.

So why are types different?

require ‘brains’

The goal of language is clarity and simplicity. You shouldn’t have to think hard about how to express your ideas; you should be focused solely on how to express them clearly.

I will never be a fan of strictly type-checked languages. That these languages allow for type coercion is a big hint that enforced type-checking is flawed, and C++ templates and Java generics are clear attempts to work around a shortcoming in the language. I know for sure that I work more slowly in strictly type-checked languages, and there is no appreciable difference in code quality.

The goal of language is correctness. You shouldn’t have to work hard to figure out how to test your ideas; you should be focused on how to prevent things from going wrong.

I quite like Ruby. However, I will never be comfortable in a language which doesn’t allow me to define interfaces (when I want to), declare exceptions (when I choose to), can optionally be configured to require all variables to at least be declared, and allow me to define types for method parameters such that when the types are violated an error occurs immediately.

Typing has its place alongside rigorous testing and solid documentation; but like testing and documentation, typing should be used judiciously. Why is this such an ideological debate?

[original publish date: 6/27/2008]


Mar 27
Democrats continue to kick Republican butt in actually, you know, running the country.

Democrats continue to kick Republican butt in actually, you know, running the country.


Formtastic without ActiveRecord

So I have been doing a fair amount of Rails development recently. I’ve been using Formtastic, which provides simple and consistent semantics for creating web forms. It’s a nice library and quite well designed. It is intended for use with ActiveRecord model objects, and trying to create forms that aren’t populating an ActiveRecord object can be challenging. The library’s author, Justin French, made an intriguing comment on StackOverflow: “It’s really not that hard to create a model instance to wrap up the concerns of your model. Just keep implementing the methods Formtastic is expecting until you get it working!”

I needed to put together a form to gather information for submission to a remote website (SalesForce). I didn’t have a model for the resulting data; that’s being tracked by SalesForce. Since I needed exactly what Justin described, I created one. He’s right, it wasn’t hard. I thought others might find it useful. Note: this will only work with Rails 3, and the example below uses HAML as the templating language.

I’ll start by showing usage. This should be pretty familiar to a Rails coder.

class ContactRequest < FormtasticFauxModel
  attr_accessor :first_name, :last_name, :company, :email, :newsletter_opt_in

  validates :first_name, :last_name, :presence => true
  validates :email, :presence => true, :email => true

  self.types = {
    :newsletter_opt_in => :boolean,
  }
end

The only unusual part is the self.types section, which I believe should be pretty self-explanatory. It gets passed through to Formtastic to inform what type of input to render, and the supported types are defined by Formtastic. This could be achieved by using Formtastic’s “:as => [type]” directive directly, but I prefer to define things once and in one place.

The ContactRequest object can now be used much like a regular ActiveRecord object. The controller manages an @contact variable, eg @contact = ContactRequest.new(params[:contact_request]), and then the view looks like any other formtastic form:

#header
  %h1 Contact Us

#body
  %h2 Contact Us
  %p Please provide the following information:
  = semantic_form_for(@contact) do |form|
    = form.inputs do
      = form_errors(@contact)

      = form.input :first_name
      = form.input :last_name
      = form.input :email
      = form.input :newsletter_opt_in, :label => "Send me the newsletter"
      = form.input :company
    = form.buttons do
      = form.commit_button :label => "Send it to me!"

All pretty standard.

So, with no further ado, here’s the FormtasticFauxModel class.

# -------------------------------------------------------------------------------
# Faux model object that plays well with formtastic; this is used for example in
# a contact form which generates a request to salesforce
# -------------------------------------------------------------------------------
class FormtasticFauxModel
  include ActiveModel::Validations
  include ActiveModel::Conversion  
  extend  ActiveModel::Naming

  # Subclass may provide a types hash.  Any attributes not listed will
  # default to string.
  # self.types = {
  #   :description => :text,
  #   :state => {:type => :string, :limit => 2}
  #   :country => :string,
  #   :newsletter_opt_in => :boolean,
  # }

  class << self
    attr_accessor :types
  end
  self.types = {}

  # So the controller can say "@contact = Contact.new(params[:contact])"
  def initialize(attributes = {})  
    attributes.each do |name, value|  
      send("#{name}=", value)  
    end
  end  

  # So form_for works correctly -- we only do "new" forms
  def persisted?  ;   false  ;    end  

  # To provide the type information
  def column_for_attribute(attr)
    FauxColumnInfo.new(self.class.types[attr])
  end

  class FauxColumnInfo
    attr_accessor :type, :limit

    def initialize(type_info)
      type_info ||= :string
      case
      when  type_info.instance_of?(Hash), type_info.instance_of?(OpenStruct)
        self.type = type_info[:type].to_sym
        self.limit = type_info[:limit]
      else
        self.type = type_info.to_sym
        self.limit = nil
      end
    end
  end
end

Enjoy!


Mar 26

The Four Horsemen of Unmaintainable Code

Sometimes when I’m writing code or designing a system, I am taking an idea and realizing it in concrete form — like a crystal forming in a liquid.

Other times when I’m writing code, I feel like I’m training an obstinate dog.

In the former case, when I am done, the result is lovely and I am proud of it.  This is why I like software; beautiful code is its own reward.  As Buckminster Fuller famously said, “When I am working on a problem, I never think about beauty. But when I have finished, if the solution is not beautiful, I know it is wrong.”

Which brings us to the other approach: “code by prayer,” also known as poke-and-check development. I find myself modifying a portion of the code, and then checking the outcome, hoping desperately that it now does what I want it to. Which it rarely does, requiring many iterations, spiraling bushes of brain-numbing complexity, and produces unmaintainable code.

Clearly this is a bad approach, but I think most developers have found themselves seduced by it from time to time. I think there are four basic causes of poke-and-check development; identifying the cause can help you get back into the palace of beautiful code.

Lack of time.

The demo is tomorrow, you have three tasks to finish, any one of which would require a day. You’ve chosen the most important one, you’re working hard, but you just don’t have time to do a careful design. You know you’re torturing your object model, but you’ll have to come back and clean up Tuesday.

Stop!

The problem here is not execution, it was prioritization. You overbid on your work; you will not succeed. Tell your product people that it’s not going to happen. Make sure you’re working on the right task. If you really need all three of those tasks done for the demo, you’re going to have to move the demo; if not, shift to testing and quality.

But please.  Stop torturing the dog.

Lack of sleep.

The demo is tomorrow, you have one task to finish, and you’re …so …close! It’s 3am, and you can’t get the last several unit tests to pass. Every time you fix one test, two others break. So you start commenting out the broken tests, because you need to commit your fixes and you don’t want to break the build…

Stop!

You are never going to get there. You are exhausted. You have pushed yourself too hard; you’re no longer effective. Go to bed, get at least a little sleep. I promise you that when you wake up, you’ll get a lot more done.

Lack of understanding

You’re in the hallway, and the product manager casually mentions a new requirement. “Oh, by the way, we need a user to be able to click on the email link and have a read-only view of the group’s posts until they log-in.”

“Great idea,” you reply, enthusiastically; you are a can-do coder. “That shouldn’t be hard. Let me go get on that — I’ll have something for you tonight!”

An hour later, you realize that the permissions model doesn’t allow for state-based permissions.

Three hours after that you realize that you’ve just opened a security hole which allows anybody with ‘temporary’ permissions to see a lot of things they shouldn’t.

Six hours after that…

Stop!

This is where the advocates for careful, well written specifications begin to get holier-than-thou, and they have a point. You agreed to do something without really understanding what was required. But the reality is that the only specification which can truly prevent misunderstanding is so thorough that, you know, it compiles and runs: only the code is complete enough to verify all the hidden assumptions. The scenario above could just as easily have started at an “iteration planning” meeting, or with “You read section 4.3.2 of the requirements document.” All of the many forms of engineering process exist to reduce the odds of this happening; but it will happen nevertheless.

Don’t blame lack of specification — and don’t be tempted to blame your ability or knowledge, either. This still happens to everyone, albeit perhaps with less frequency with experience and careful process. But it will still happen.

The problem here is subtle: by the time you realized you had underestimated the complexity of your undertaking, you were already committed to it. You had set expectations, one way or another; and worse, you were emotionally invested in what you were doing. It’s a cool feature! It will be good! You need to get it done.

Perhaps; but when you find yourself coding by prayer, you are setting yourself back. You need need to re-evaluate the assumptions, and regain control of the code. You may find that you’re on the right track; but until you step back and think it through, you are far more likely to find that you’re creating a mess that will need to be ripped out and replaced later.

Use of CSS

You are working on the front end of a website, and you discover that adding a ‘left’ or ‘position’ value to a floating div flings it across the window and reflows everything along the bottom of the screen.

Sadly, I can’t advise you to stop. CSS is evil, but it’s an unavoidable evil. It is being applied in ways that it was never intended and was not designed for. The fact that horizontally or vertically centering a div is hard and confusing reflects the ways that the ‘box model’ is not adequate for today’s websites.

This is only somewhat tongue in cheek, by the way.  CSS development really does require poke-and-check development; the only workable answer here is to get a really good CSS editor, one which updates the display in real time as you modify the code.

Stop Doing That!

“Let the poets write that he had the tools of greatness, but the voices of his better angels were shouted down by his [demons].” (Aaron Sorkin, “The West Wing”).

I have come to recognize the temptations of poke-and-check coding; it is always, always, always a demon tempting me to torture my code into submission. Or that I’m using CSS again.

So if you find yourself coding by prayer…

Stop doing that!


Mar 25
“It is not the critic who counts; not the man who points out how the strong man stumbles, or where the doer of deeds could have done them better. The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood, who strives valiantly; who errs and comes short again and again; because there is not effort without error and shortcomings; but who does actually strive to do the deed; who knows the great enthusiasm, the great devotion, who spends himself in a worthy cause, who at the best knows in the end the triumph of high achievement and who at the worst, if he fails, at least he fails while daring greatly. So that his place shall never be with those cold and timid souls who know neither victory nor defeat.” Theodore Roosevelt (1858-1919)

Oct 8

Using SSL is …not as easy as it should be.

Wow.

Rails is a powerful framework, and many common things are made easy. For a professional website, using SSL judiciously is very important, particularly in an era of social networking and instinctive trust of sites with personally identifiable information (eg, phone numbers). But Rails does not make it easy to use SSL. So, in an effort to save someone else a few days of internet searching, here are the four steps needed to use SSL with Rails on your site. I am not going to discuss how to get the certificates and/or set up Apache to use SSL (see reference below for a reasonably good article on that topic). No, I discuss here only the comparatively straightforward task of redirecting requests to HTTPS and/or designating that forms must be sent via SSL. This is not as simple as ‘use the ssl_requirement gem’. Not by a long shot.

What we want to do

SSL assures information privacy. As data flows back and forth between the server and the client, it is passed between many intermediating servers, any of which might not be friendly and store, inspect, and misuse the information. So it’s important to encrypt anything which might be misused. However, we don’t want to encrypt everything, because encryption and decryption takes a fair amount of processing overhead, which both slows things down and adds unnecessary load to the server. It’s important to remember that the information flows both directions: it flows out to be displayed on screens, and then the end user may type data into forms and information flows back in. So the goal here is to selectively decide when to use encryption (via HTTPS) and when to use the lighter-weight, unencrypted HTTP. There’s one more wrinkle to this. As I mentioned, I’m not going to discuss how to set up your servers and get certificates and so on. There are a few reasons for this, but one of them is that setting all of that up sucks hard. Like, hours of frustrating tweaking of inscrutable directives, with limited ability to debug, exactly the sort of irritating development stuff we went to Ruby and Rails to avoid. Which is to say, you don’t want to use SSL except when you absolutely need to, and you definitely don’t want to have to set it up every time a new developer joins your team or your box fails and you discover that you’ve misconfigured Time Machine so it isn’t backing up your /etc directory — sorry. I digress. Point being, we don’t want to use SSL in development.

Step 1: Outbound information

Ok, this looks easy at first blush. Rails knows the protocol that the arriving request used (in this case, either “http://” or “https://”). Well, it will if the proxy server was configured correctly and sets X-Forwarded-Proto in the request. But again, I’m not talking about that here. Since Rails knows the protocol, it knows what environment we’re running in, and it certainly knows how to redirect requests, so there are many articles which suggest that all you need to do is redirect to or from the right protocol. However, the important trick here is that you can’t simply redirect :protocol => "https://", because that will lose any parameters in the request. So you need to be careful to include all the parameters in your request. Without further ado, a pair of filters and a helper. I add these to my ApplicationController:

  # Usage: before_filter :require_ssl, :only => [:some_method]
  def require_ssl
    redirect_to params.merge!(:protocol => "https://") unless request.ssl? or !use_ssl?
  end
# Usage: before_filter :no_ssl, :only => [:some_method] def no_ssl redirect_to params.merge!(:protocol => "http://") if request.ssl? end
# If you need to test SSL, you may want to configure it up on a development box # App::Config is a separate post, let me know if you want me to write it up def use_ssl? !local_request? || App::Config.ssl_for_local end
So I think the comments are more or less self explanatory, but in case they’re not… By default, all controllers will happily accept both SSL and non-SSL requests. You can use these filters to flip a request to the right protocol; before_filter :require_ssl for private information, and before_filter :no_ssl for the more common, low-energy requests. I also add a before_filter :no_ssl in my ApplicationController, since I’d rather be conservative about resource consumption. If you’re more worried about information leak, you can define the opposite default. If you do define a default, don’t forget to add the corresponding skip_filter when you want to change the protocol. The params.merge! is tricky and very important. When I first deployed my service with SSL… in production…. with inadequate testing… I did the simple redirect_to :protocol => "https://" and I had some key requests redirect to localhost! That was not a good thing. You want to keep all the params of the original request, just change the protocol. The use_ssl method is clever, and I wish I had thought of it myself (see below). If the request originates from the local box, there’s no point in using SSL; it turns out, that covers your development box quite nicely. However, that also means that when you’re setting up your service, you can have problems that are only discoverable in production (or, we hope, integration); so when I am working on actually putting the SSL in place, I (sigh) configure my local box for SSL and test the hell out of it. Because I don’t want to redirect my customers to localhost ever again.

Step II: Inbound information

Most of the sites I’ve seen discussing this topic present a variant of the filters above and then claim victory. However, you probably don’t want to be sending your passwords across in plaintext, which means you need to make sure that they use https when appropriate. Your login page is hit very frequently, and you probably don’t want to require that it use https. So we want to be able to render a page via http, and then submit the form via https. I struggled with this for a while; many of the built-in Rails primitives flat out suck when presented with a :protocol option. So the best I could come up with was to write a reasonably flexible façade over them. If I were more motivated, or more experienced, I would probably have dug into the Rails source and fixed this, but I’m neither. First, let me show you the usage. Consider a typical form (in this case, a :user has_many :contact_data):

  - form_for([@user, @contact_datum]) do |f|

We want to modify this as little as possible. Ideally we’d just add the :protocol to the form_for, but sadly that just don’t work. The best solution I was able to come up with, after a fair amount of web research, coding, and swearing, was the following:

  - form_for([@user, @contact_datum], {:url => ssl_url_for([@user, @contact_datum])}) do |f|

I put this in my ApplicationHelper:

  # This is a simplified RESTful route generator.  Given an object, it generates a URL (via url_for)
  # and defines the full URL including protocol if the requested protocol doesn't match the current protocol.
  # By default it will use the ssl protocol defined by the ApplicationController.ssl_protocol method
  # 
  # +objects+ an object or array of objects similar to those passed to a form: [@container, @target].
  #                We allow the target to be an integer, in which case we assume it's an object id and require
  #                that the action and controller be specified explicitly (see below)
  # +action_name+ (optional) the action to invoke.  If not supplied, :create or :update is inferred from
  #                          whether the target is new or has been saved.
  # +options:+
  #    :controller => <controller> the name of the controller, eg :users
  #    :protocol   => "http://" to force a non-SSL form submission from an SSL rendered page
  # 
  def ssl_url_for(objects, action_name = nil, options = {})
    objects = Array(objects)
    target = objects.pop
    # We're almost always going to want to use SSL, but not on my local box and 
    # not if the user demands something else
    protocol = options[:protocol] || (use_ssl? ? "https://" : "http://")
    # If no controller is specified, infer it from the class of the target
    controller_name = options[:controller] || target.class
    controller_name = pluralize(controller_name.to_s, 2).underscore
# If the target isn't numeric, infer the action_name (if not specified) from the target's state if !target.kind_of?(Numeric) action_name ||= target.new_record? ? :create : :update end
url_hash = { :controller => controller_name, :action => action_name, :protocol => protocol, } # grab an id, unless the target is a new object, in which case there is no id to be grabbed if target.kind_of?(Numeric) url_hash[:id] = target else url_hash[:id] = target.id unless target.new_record? end
# If the protocol we want doesn't match the protocol for the page we're, we need to render the full URL url_hash[:only_path] = false unless (request.ssl? ? "https://" == protocol : "http://" == protocol)
# For each of the remaining objects in the original array (if any), add a reference to its id by class objects.each {|object| url_hash["#{object.class}_id".downcase.intern] = object.id}
# Whew. That was easy. Render me a URL! url_for(url_hash) end

So that’s not nearly as self-explanatory, and I’m afraid I’m not going to do a lot more to explain it than the comments in the code itself. Most of it is syntactic sugar so I can use the same method with an object or an id as appropriate.


Thanks to:


Jul 31

Rates of employment growth, by president

I don’t think anything needs to be said other than Krugman’s original caption: “There’s something happening here…”

F3DD13D0-34CC-44F6-8DAD-6256320581D5.jpg


Page 1 of 2