Archive for 2011

Responding with the contents of a JSON file in Rails

No Comments »

I have a schedule.json file that I want to dump to the browser for testing purposes.

This took entirely too long for me to sort out through trial and error, but here it is:

#/app/controllers/some_controller.rb
def schedule
    render :file => "#{Rails.root}/app/assets/resources/analytics/schedule.json",
      :content_type => 'application/json',
      :layout => false
end

“Could not prepare files for refactoring” in VS2010

No Comments »

When attempting to refactor in VS2010 a message box will appear with the message "Could not prepare files for refactoring".

This is a mildly aggravating bug that I had found a solution for a couple years ago and then promptly forgot. Since moving all my development to virtual machines on my Macs though it has resurfaced - mo' VS installations, mo' problems.

In this case I had a project that is using the Microsoft Web Deployment project. When I went to load our solution up for the first time of course that project type was missing so I searched for it and the first link that comes up is the beta released in April 2010. So I installed that. Whoops.

What you really want is the "Visual Studio® 2010 Web Deployment Projects - RTW" whatever the fuck RTW means [I know its release to web, but seriously, stop will the nonse release acronyms]. You can find it here:

http://www.microsoft.com/download/en/details.aspx?id=24509

You'll need to uninstall the beta if you have it installed before installing the final version.


Fighting ExtensionDataObject with JavaScriptSerializer for fun and profit

No Comments »

I guess the title is a little misleading because there is seldom any fun to be had with the .NET Framework.

But if you've got a Linq to SQL *.dbml and the tool is generating those swell ExtensionDataObject properties preventing you from easily serializing your model classes to JSON and you don't want to make shadow classes (::gasp:: yes I know the .NET Fx loves ceremony, I however do not) then you can use a custom JavaScriptConverter to ignore those properties. When you have control of a class you can put a NonSerialized attribute on properties but that becomes substantially more difficult when a tool is responsible for generating the class file and cheerfully overwrites any changes you may make if you even open the file to glance at its contents. Yes shitty *.dbml tool in Visual Studio, I'm looking at you.

So let's say you have this simple helper class:

// JsonSerializationUtility.cs
public static class JsonSerializationUtility
{
	public static string ToJson(this object obj, string wrapper = null)
	{
		var json = new JavaScriptSerializer().Serialize(obj);
		if (!string.IsNullOrEmpty(wrapper))
			json = "{ \"" + wrapper + "\": " + json + " }";

		return json;
	}

	public static T Deserialize<T>(string json)
	{
		var jss = new JavaScriptSerializer();
		jss.RegisterConverters(new [] { new ExtensionDataObjectConverter() });
		var result = jss.Deserialize<T>(json);
		return result;
	}
}

... then you'll need this handy ExtensionDataObjectConverter class!

// ExtensionDataObjectConverter.cs
public class ExtensionDataObjectConverter : JavaScriptConverter
{
	public override IEnumerable<Type> SupportedTypes
	{
		get
		{
			return new ReadOnlyCollection<Type>(new [] { typeof(ExtensionDataObject) });
		}
	}

	public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
	{
		return null;
	}

	public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
	{
		return null;
	}
}

Proxying around remote JSON HTTP GET with Sinatra

No Comments »

If you have a remote host that has some JSON data you need you can very quickly and easily proxy that host's response using Sinatra. This is useful for local development. There are other ways to do this of course, but in a pinch the following solution works, albeit without error handling.

#./server.rb
require 'net/http'

HOST = 'example.com'

get "/package/details.json/:id" do
  content_type "application/json"
  uri = URI::HTTP.build(
        :host  => HOST,
        :path  => "/package/details.json/#{params[:id]}",
        :query => 'some_parameter=abc'
  )
  Net::HTTP.get(uri)
end

get "/simulate/details.json/:device_identifier" do
  content_type "application/json"
  uri = URI::HTTP.build(
    :host => HOST,
    :path => "/simulate/details.json/#{params[:device_identifier]}"
  )
  Net::HTTP.get(uri)
end

backbone.js: Collections of Models within Models

No Comments »

This isn't your typical backbone.js scenario but its fortunately easy to solve, and special thanks to Joey Beninghove for shaving several hours of hard work off my plate by helping me arrive at a solution.

My problem domain is this: we (by we I mean an intern at my company) are building a tool that displays this structure called a package. The package looks something like this...

 package
|- nodes [0..n]
    |- node
        |- assets [0-n]
        |   |- asset
        |- actions [0-n]
            |- action

Essentially a tree of collections. Behind the scenes all of these models (package, node, asset, action) are full blown models. In this particular case though we wanted to display the structure of a package which means we get the entire package's JSON all at once, like a giant turd (snippet):

{
  "CreateTime" : "/Date(1283319058700)/",
  "Id" : 10000,
  "ModifyTime" : "/Date(1283319060013)/",
  "Name" : "Some Package Name",
  "Nodes" : [ { "Actions" : [ { "FromNodeId" : 53730,
              "Name" : "Dismiss",
              "ToNodeId" : 0
            },
            { "FromNodeId" : 53730,
              "Name" : "View",
              "ToNodeId" : 53731
            }
          ],
        "Assets" : [ { "AssetBinaryId" : null,
              "AssetClass" : { "Id" : 8,
                  "Name" : "ImageURL"
                },
              "AssetFormat" : { "Id" : 1,
                  "Name" : "PNG"
                },

              "Data" : "/SomeUrlHere?querystring",
              "Id" : 52616,
              "Name" : "Banner Image",
              "NodeId" : 53730,
            } ],
        "Name" : "Banner",
        "NodeClass" : { "Id" : 1,
            "Name" : "Banner"
          }
      },
⋮
}

As I was working the solution at the time in a regular HTML file I was relying on console.log and Safari's excellent developer tools. (Note: to retrieve JSON data from a local file in Chrome you have to launch Chrome with a command line argument.) The solution looks something like this (without worrying about the Router or Views):


<html>
⋮
  <head>
    <script type="text/javascript" src="js/vendor/backbone/underscore.js"></script>
    <script type="text/javascript" src="js/vendor/jquery/jquery-1.6.2.js"></script>
    <script type="text/javascript" src="js/vendor/backbone/backbone.js"></script>
  </head>
  <body>
    <script type="text/javascript">
window.Action = Backbone.Model.extend({
  initialize : function() {
    this.fromNodeId = this.get('FromNodeId');
    this.toNodeId = this.get('ToNodeId');
    this.name = this.get('Name');
  },
  nextNode : function(nodes) {
    return nodes.detect(function(node) { return node.id == this.toNodeId}, this);
  },
  previousNode : function(nodes) {
    return nodes.detect(function(node) { return node.id == this.fromNodeId}, this);
  }
});
window.Actions = Backbone.Collection.extend({ model: Action });
window.Asset = Backbone.Model.extend({
  initialize : function() {
    this.assetBinaryId = this.get('AssetBinaryId');
    this.data = this.get('Data');
    this.id = this.get('Id');
    this.name = this.get('Name');
  }
});
window.Assets = Backbone.Collection.extend({ model: Asset });
window.Node = Backbone.Model.extend({
  initialize: function() {
    this.assets = new Assets(this.get('Assets'));
    this.actions = new Actions(this.get('Actions'));
  },
});
window.Nodes = Backbone.Collection.extend({ model: Node });
window.Package = Backbone.Model.extend({
  initialize : function() {
    // the following line forces 'this' to refer to the Package instance in the
    // function `fetch_success`
    _.bindAll(this, 'fetch_success');
    this.bind('change', this.fetch_success);
  },
  // specifying the URL as a function gives us a bit more flexibility
  url : function() {
    return "data/package/" + this.id + ".json"
  },
  // invoked automatically when the change event is invoked which happens when fetch is successful
  fetch_success : function() {
     this.nodes = new Nodes(this.get('Nodes'));
     this.createTime = this.get('CreateTime');
     this.modifyTime = this.get('ModifyTime');
     this.name = this.get('Name');
  }
});

<!-- and... -->
$(document).ready(function() {
  pkg = new Package({id:"10000"});
  pkg.fetch({ failure: function(model, response) {
    console.error("ERROR");
    console.log(response);
  }});
    window.pkg = pkg;
    console.log(pkg);
  </script>
  ⋮
  </body>
</html>