Using ostruct to interface with REST

Have you ever had to work with an external API such as twitter or facebook, those two should be pretty easy to interface with by now as there are plenty of wrappers such as koala.

But let’s say the API we are working on is a client’s API or the API for an obscure service.

What we want is for JSON requests to relate to ruby objects.

This is where ostruct comes along, ostruct takes a hash and converts that to methods that can be accessed as they were from an activerecord object for example.

What you can do is something similar to this.

query = "/notes/1"

c = Curl::Easy.perform(query) do |curl|
  curl.headers["X-Auth-Token"] = "my_auth_token"
end

my_hash = JSON.parse(c.body_str)

ostruct = OpenStruct.new(my_hash)

In this example i used curb to send an x-auth header to the “secret” api, and then passed the parsed json hash to ostruct.

Now rather than having to handle the json api like this in your views

<%= my_hash[:my_attrib] %>

You can use you json data like so

  <%= my_ostruct.my_attrib %>

This way if your boss falls out with the api company and wants you to re-implement the data in your rails app, all your view logic will be compatible with activerecord for example.

In my production code the post, get (other CRUD actions if needs be) and login actions are abstracted into a separate class and is inherited by each model.

Rails 4.0 Wishlist

    TL;DR Maybe I’m an idiot, but I’m looking at Rails from a beginners point of view.

  • Routes defined in the model, maybe as: and :via attributes would suffice.

    Maybe like this:

    class User < ActiveRecord::Base
      Route :author # this could probably be accessible from a controller in params
      Route :reader
      Route :moderator
    end

    *following a few posts below, we agree that something like this should be in the controller instead

    or

    class Book < ActiveRecord::Base
      Route :novel, :via => :author # this would give you; /novel/arthur_conan_doyle/sherlock_holmes_the_hound_of_the_baskervilles
      Route :mystery, :via => :hero # would give you /mystery/sherlock_holmes/the_hound_of_the_baskervilles

      ... # friendly id code
    end
  • A Routes admin panel/sitemap, to see if those routes are setup correctly, something like resque. or maybe a tree structured ‘rake routes’ or a instrumentation panel like the top command to see when routes are being accessed.

    i’ve not specified the value for the ‘:user’ and ‘:house’ hashes as their path should be implied by the route setup and passing them should not be needed.

  • An interactive mode for migration generators, so that you don’t have to track table names and column names down. For example; new, remove, add and delete generators.
  • Generators which have to option to include annotations linking to the related file paths in comments, for example: in a controller have “# ../views/modelname/edit.html.erb” just above the edit action so that a ‘gf’ in vim just sends you there or a click in sublime text or another editor.
  • Api only generators, so the generated controllers and models have an api specific output (no views, token driven), maybe backbone aware?

    Maybe creating a backbone app as default, by having api and backbone model generation.

    Backward compatibility for decoupled webapps; for example using v8 or therubyracer to create an old school app for when the user’s browser fails a certain prerequisite, i.e. serverside backbone.

  • View-specific assets, i.e /views/foo/index.html.erb will load from the following:
    /assets/javascripts/views/foo/index.js.erb
    /assets/views/foo.js.erb
    /assets/application.erb.js
    this is to prevent javascript logic from unrelated views loading in the wrong places, this is more for cleanliness in the head than for security through obscurity.
  • A nested view structure:
    If my resources are nested like so

      resources :users do
        resources :books do
          resources :chapters
        end
      end

    I should be able the structure my views like this; “app/views/users/books/chapters/index.html”

    Those nested resources would probably have to work like partials.

    Routing errors should be more descriptive, show the previous view, current view and controller in the error, the glaring error might just be obvious immediately.

    How about adding a queries to routes as a replacement for path helpers.

    Instead of something like this

      user_house_room_path(room.user_id,room.house_id,room.id)

    as you noticed the first two parameters are just taken from the last parameter in that instance and should just be “implied”, maybe we should have something like this:

      path_for :user, :house, :room => room.id

    Or maybe like this:

      edit_galaxy_system_planet_path(galaxy.id, system.id, planet.id)

    In this example the path could be based on the order of the system in a galaxy and the planet number in a solar system instead.

    But instead if using path helpers, we could have a path “finder”

      Path(:edit, :galaxy => :id, :system => [:x, :y, :z], :planet => :number)

    But if the last parameter is :id, then the galaxy id, and system coords would be surplus to requirements and the path finder should be able to figure that out and shorten the url (if that route is defined in routes.rb or defined in a controller) and probably show a warning.

    Or what about just adding a `path` method to models for example you can do

    redirect_to @book

    so why not have a path method like

    redirect_to @book.path(:via=>:author)

    or something to that effect.

  • a decoupled “view app” that only contains views, assets and mock controllers to hand off to designers (maybe for outsourcing purposes) that you can copy and still run, possible using something like Sinatra in that layer.
  • make renaming an application easier, by removing the need for the apps namespace all over the place, or by having a ‘Rails rename’ command.
  • prettier error messages, for example “missing page” could load a placeholder (sometimes you just want a page to debug to)
  • Rails generator history, I often come across a demo app that does what I am looking for but I will then have to trawl through the git commits to see how that app applies to my app, I am ok with copying files and modifying them for my needs but when it comes to files that have been created via a generator then they are hard to duplicate. I propose the rails generations are logged in a file so that it can be used later to create a step by step tutorial.