Michael Sofaer's blog



Michael SofaerMichael Sofaer
Standup 6/23/2011: The Only Way to be Sure
edit Posted by Michael Sofaer on Friday June 24, 2011 at 12:41AM

Ask for Help

"Why did my .profile stop being sourced? It still works if I source it by hand.

You may have created a .bash_profile, which supercedes the .profile. One solution is to include your .profile from your .bash_profile. A pattern we sometimes use for this is to include every file in ~/.bash_profile_includes from the .bash_profile

"How do I get bash to automatically answer yes to questions programs ask?

There are various ways to do this, but the short answer is to use the "yes" program built into bash. yes | my_program

"How do you delete a file called ~ Not by typing rm -rf ~ The simplest thing is to do this through the OS file system GUI.

Interesting Things

Canvas Slow on Chrome

Canvas can get very slow on Chrome sometimes. If this happens, the only thing found to work so far is to delete the Library/Application Support/Google directory

Facebook Connect De-Auth rules

It was claimed that when a user de-authorizes your Facebook application, the Facebook API terms of service require you to delete all data about the user that you got from the API. This includes fields you pre-filled that the user then submitted.

Facebook does provide you with a de-auth callback if you want one, but there is no explicit mention of it in the ToS. The ToS does say you must remove user data "upon request" and that you have to provide a way to make such a request.

Michael SofaerMichael Sofaer
Presenters and Logical APIs
edit Posted by Michael Sofaer on Tuesday September 21, 2010 at 10:08AM

MVC in Rails and Thick Views

The default way of using ActionController and ERB in Rails is to pass models into your views, and let the views figure out what to render and where. There's been some pushback in the community on this, people are talking about getting rid of "thick views" with logicless templates like Mustache. Mustache is awesome, but if thick views are the problem, we don't need to go that far if we just change the way we think about controllers a little bit.

Thick views are a controller problem

Consider this ERB, using a loop instead of partials for illustration:

<%@posts.each do |post|%>
  <%=post.author.name%>
<%end%>

If we write our controller like this, the controller will do two queries:

@posts = Post.all(:include => :author)

If we write our controller like this, it will do only one query in the controller:

@posts = Post.all

And the view will do as many queries as there are posts. I'm sure you've seen code like this in projects you have worked on. In the standard Rails model, we pass ActiveRecord objects to our views, they might or might not be pre-populated, and thin views can be hard to tell from thick views.

We can explicitly test this by mocking Post and counting queries, but that is a lot of extra work, and you have to remember to do it everywhere.

APIs are unit testable

In contrast to standard controller tests, the result of a JSON API call can be declaratively described. The difference between

{:posts => [:id => 4, :title => "Jerusalem", :author_id => 33]}

and

{:posts => [:id => 4, :title => "Jerusalem", :author => {:name => "Josephus, :id => 33}]}

Is pretty clear, and easy to assert on. If we TDD our controller methods this way it protects us from a lot of the n-query problems in views.

API work comes too late

I've seen serveral teams experience pain because Rails does not make it easy to develop a JSON API alongside your HTTP controllers. Rails 3 is better than Rails 2 on this, but you still have to handle the cases separately, particularly as things get more complex.

Twitter is a good example of this. The HTML endpoint recently started consuming its own JSON API over HTTP for generating pages:

One of the most important architectural changes is that Twitter.com is now a client of our own API. It fetches data from the same endpoints that the mobile site, our apps for iPhone, iPad, Android, and every third-party application use. This shift allowed us to allocate more resources to the API team, generating over 40 patches. In the initial page load and every call from the client, all data is now fetched from a highly optimized JSON fragment cache.

This is a very cool pattern in general for a web application. Consuming your own API keeps your business logic in one place, separate from your display logic. And caching on JSON API calls can be easier than caching after building HTML. Obviously you don't want to run two processes when you're getting started, but we can take inspiration from this as we organize our code.

The Presenter pattern

A Presenter is a controller that delivers data rather than objects. People like Martin Fowler have been talking about this for a while, and Twitter recently announced a major technical change along these lines.

From the Wikipedia article on "Presenter First", which is mostly aimed at desktop design, but is applicable to the web, too:

When used in GUI applications, this approach allows the presentation logic and business logic of the application to be developed in a test first manner decoupled from on-screen widgets. Thus, the vast majority of the application programming can be tested via unit tests in an automated test suite. In so doing, the reliance on GUI testing tools to perform extensive system testing can be reduced to verifying basic GUI operation or eliminated entirely.

Unlike standard Rails TDD, if you construct your page data as an API call, your controller tests can now assert directly on that data, instead of the objects that your templates can query with. Testing on a data dictionary is more declarative, and it helps you write thinner views.

Make your view a logical client of your API

We can use the Presenter pattern in Rails by having our controllers call the methods that generate our JSON API at the moment right before serialization to a string. That way there is only one code path that does business logic, which solves the divergence problem.

Vanna

Vanna is an exploration of how MVP can work in Rails. It's not fully functional (in particular it needs a way to do non-200 returns), but it is enough to illustrate the point. Mixing Vanna into ActionController::Metal restructures controller flow to mimic JSON API calls. Your controllers wind up looking like this:

class VillainsController < ApplicationController
  def index
    {:main => {"villains" => Villain.all}}
  end

  def show(opts = params)
    villain = Villain.named(opts["villain"]).first
    sidebar = catchphrases("villains" => villain["partners"])
    {:main => {:villain =>villain, :sidebar => sidebar}}
  end

  def catchphrases(opts=params)
    names = opts["villains"]
    Villain.named(names).map{|p| p["catchphrase"]}
  end
end

How does this differ from a standard Rails controller? For one thing there's a silly "catchphrases" method, which is a placeholder for an API method that gives a set of fields for a set of records:

def catchphrases(opts=params)
  names = opts["villains"]
  Villain.named(names).map{|p| p["catchphrase"]}
end

This is structured like an API call. It expects to take in a set of keys, and return some subset of fields on the objects with those keys. Exactly the sort of thing an API does, but not something that you usually see in web apps in their early stages. There's also an explicit (opts=params) in the signature. Let's take a look at the show method to see why that is there:

def show(opts = params)
  villain = Villain.named(opts["villain"]).first
  sidebar = catchphrases("villains" => villain["partners"])
  {:villain =>villain, :sidebar => sidebar}
end

On the second line of the method we are explicitly calling one method in a controller from another, passing a params hash (suggested by Richard Crowley). We construct a data dictionary for these smaller calls and pass it through to our template.

Here's what the view looks like:

<div id=main style="width:70%;float:left;border:black 5px solid;">
  <ul>
    <li><%=villain[:name]%></li>
    <li><%=villain[:catchphrase]%></li>
  </ul>
</div>
<div id=sidebar style="width:20%;float:right;border:black 5px solid;">
  <% sidebar.each do |catchphrase| %>
    <%=catchphrase%> <br/>
  <% end %>
</div>

This looks almost exactly like a standard Rails ERB template, except that the top level objects available to you are accessed as locals, not with an @.

API for free

Vanna makes all your controller methods available as API calls automatically. Because you are explicitly returning a data dictionary, there's no need to have a different code path for your HTML and JSON. The only difference is whether you go to ERB, or call to_json on the dictionary. So now we can do our controller tests as API tests (the tests in Vanna itself are a little different):

 def test_catchphrases
   header "Accept", 'application/json'
   get "/villains/catchphrases?villains=luis"
   assert{ JSON(last_response.body) == ["Hungry like the volcano!"] }
 end

So OK, we can call our catchphrases method as a JSON call.

def test_show_has_catchphrases
  header "Accept", 'application/json'
  get "/villains/show?villain=luis"
  assert{ JSON(last_response.body)["main"]["sidebar"] == ["You're gonna get punted!"] }
end

And the same data is available inside the larger call which includes it.

def test_html_has_sidebar
  get "/villains/show?villain=luis"
  assert{last_response.body.match(/div id=sidebar/) != nil }
end

And the template actually renders out the sidebar.

Now we have a single data retrieval code path, that breaks off into HTML right before we actually render HTML.

The code for Vanna is on Github, but here's the meat of it:

module Vanna
  def self.included(klass)
    raise "#{klass.name} does not inherit from  ActionController::Metal" unless  klass.ancestors.include?(ActionController::Metal)
    klass.send(:include,  AbstractController::Layouts)
    klass.send(:include,  AbstractController::Callbacks)
    klass.append_view_path "app/views"
    klass.class_eval("def logger; ActionController::Base.logger; end;")
  end

  def process_action(method_name, *args)
    run_callbacks(:process_action, method_name) do    dictionary = send_action(method_name, *args)    dictionary = @layout_pieces.merge(dictionary) if @layout_pieces  && dictionary.is_a?(Hash)    self.response_body = request.format.symbol == :json ?
 dictionary.to_json : html_render(dictionary)
    end
  end
  def html_render(dictionary)
    render(nil, :locals => dictionary)
  end
end

It's an example more that a real tool - it's a demonstration of a valuable way to think about building web applications.

Try it out

It's extremely rough still, but it serves pages. Here's the setup:

Gemfile

gem 'vanna', :git => 'git://github.com/MikeSofaer/vanna.git'

ApplicationController

Change 'ActionController::Base' to 'Vanna::Base'

layouts/application.html.erb

Remove the javascript_include line. (and if you know what to do so this isn't necessary, tell me.)

Michael SofaerMichael Sofaer
Standup 06/18/2010: ActionMailer day
edit Posted by Michael Sofaer on Friday June 18, 2010 at 02:48PM

Ask for Help

"How can I turn off logging of email attachments in ActionMailer?"

You're not the only person ever to ask that.

Actionmailer's deliver method looks like this:

     # File vendor/rails/actionmailer/lib/action_mailer/base.rb, line 473
473:     def deliver!(mail = @mail)
474:       raise "no mail object available for delivery!" unless mail
475:       unless logger.nil?
476:         logger.info  "Sent mail to #{Array(recipients).join(', ')}"
477:         logger.debug "\n#{mail.encoded}"
478:       end
479: 
480:       begin
481:         __send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
482:       rescue Exception => e  # Net::SMTP errors or sendmail pipe errors
483:         raise e if raise_delivery_errors
484:       end
485: 
486:       return mail
487:     end

And the actual delivery methods look like this:

     # File vendor/rails/actionmailer/lib/action_mailer/base.rb, line 594
594:       def perform_delivery_smtp(mail)
595:         destinations = mail.destinations
596:         mail.ready_to_send
597:         sender = mail['return-path'] || mail.from
598: 
599:         Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain], 
600:             smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
601:           smtp.sendmail(mail.encoded, sender, destinations)
602:         end
603:       end

If you compare lines 477 and 601, you will see that they both hook directly into the "encoded" method on the Tmail object. If you want to fix this, you're going to have to patch (or monkeypathch) ActionMailer


"Why is Selenium running tests before Jelly has finished loading?"

The answer to this was that Webrat has a waiting period, and if you have a long load time you need to increase it.

try this to fix your selenium timeout problem (in your selenium_spec_helper.rb or equivalent):

Webrat.configure do |config|
  config.mode = :selenium
  config.selenium_browser_startup_timeout = 60
end

Interesting Things

  • RVM hooks into Textmate. You can set up Textmate to run tests using an RVM Ruby. See this, for example.
  • There are WWDC videos on iTunes if you have a Developer account.
  • Garbage Collection: If you are using REE you need to pay attention to your garbage collection strategies. Even at low load levels it can make a difference in request time.
  • Syslog-ng templates: If you have multiple servers, and you are using syslog-ng and Splnuk (you should be) you can format your syslog-ng log lines using templates.
  • mail_safe: This is a gem that whitelists domains so all outbound email instead goes to you. Just install it and then
    config.gem mail_safe
    Of course, if you do this in production your emails won't work. Use it wisely.