Friday 13 December 2013

Ember.js and Rails - pt 3/x

Fixing ActiveModelSerializer in Ember-Data

Just a quickie... I need to write a longer post after the significant help I got yesterday from Ember dude Eric Berry.

But I did manage to figure out using the DS.ActiveModelSerializer. There is an entry in the Transition Doc of Ember Data talking about using underscores.
It seems the DS.RESTAdapter now defaults to expecting camelCase'd class names. And the DS.ActiveModelSerializer does not fix this (thereby NOT working with Rails' ActiveModelSerializer out of the box - well done guys!). Also, the aforementioned document section is completely wrong.

This is what you need to do somewhere (I put it in store.js) to get it to work with Rails' ActiveModelSerializer:

App.ApplicationSerializer = DS.RESTSerializer.extend({
  typeForRoot: function(root) {
 var camelized = Ember.String.camelize(root);
 var s = Ember.String.singularize(camelized);
        var deCs = Ember.String.decamelize(s);
// console.log(root + "; " + camelized + "; " + s + "; " + deCs);
 return deCs;
  }
});

I still need those nasty 'key:' entries on the rails side though to make associations work. But I am guessing it is something similar causing the problem.

We're all in this together.

Tuesday 10 December 2013

Ember.js and Rails - pt 2/x


Ok, it's been a couple of weeks (this is not the only thing I'm working on) and not too much progress. Getting my head around Ember has been a nightmare, not helped at all by the fact it is a moving target, especially in the case of Ember-Data.
So much of a moving target that the whole thing shifted into RC mode.
So, a lot of changes have had to be made.

Die, Coffeescript, Die Die Die.


The other thing is I cannot express deeply enough my hatred of Coffeescript. It seems, well, pointless. It seems to be used to write Javascript and I really don't see any advantages over just writing Javascript. It is argued that it is smaller, but that is not really the point when it is unreadable.
It is like I say that I write my letters in Japanese, which will eventually be converted to English, because in Japanese I can use a single Kanji character to express a whole word or concept in English. The fact that you have to learn Japanese to accomplish something you could adequately do from the start is the killer.

So, I have ditched Coffeescript for now.

Ember Store

So, the store.js file now looks like this:

HorseFeeder.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace: 'api/v1'
});

Lesson #1 - don't use DS.ActiveModelSerializer

If I put this line in:

HorseFeeder.ApplicationSerializer = DS.ActiveModelSerializer.extend({});

everything stops parsing. Even though I am using ActiveModelSerializer on the Rails side.

Routes

Routing has changed in Ember-Data. It's a little simpler, but, they got rid of the store object, which means that you can't call the store directly from Firebug.

Routes now look like this:


HorseFeeder.EventDaysIndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('event_day');
  }
});

HorseFeeder.EventDaysShowRoute = Ember.Route.extend({
  model: function(params) {
    obj = this.store.find('event_day', params.event_day_id);
 return obj;
  }
});

Serializers

Right now it looks like this (see 'current crisis points' below):

class EventDayIndexSerializer < ActiveModel::Serializer
  attributes :id, :day
  has_many :events, embed: :ids, key: :events
end 

Note that if I don't do that key:  :events thing Ember doesn't see the objects.

Current Crisis Points

Right now the backend is spewing out data and the front end is taking it. i.e. I am doing what all the Ember tutorials on the web do. But that is not the real world. Here are a list of my current pain points

  1. When I send out a list of objects in an index call, I do not want to send out all their associations/children because that would mean basically dumping the whole database, right?! As all objects are related to each other in my model it is unmanageable and slow. I am fixing this right now by writing serializers that only dump out the object, not the children.
  2. If you do what I do above (with the limited data at the index level) I cannot figure out how to get Ember to reload the object on the 'show' so I can fill in all the data. To me this seems to be such an obvious way to do it I can't believe I've spent 2 days trying to get it to work.
  3. What doesn't the ActiveModelSerializer in Ember work for AMS in Rails?
  4. The pain and time so far have caused me to question the wisdom of using Ember!
I have a few open StackOverflow questions... so hopefully my next instalment will be all sweetness and light.

Learning Ember.js and Rails Part 1 (of many!)

I’m starting on a new, massive, application. I don’t like to make things easy on myself so instead of doing this in my usual RoR/jQuery stack I am jumping in and doing this with:
  • Ruby 2
  • Rails 4
  • Ember.js
This presents some challenges, not the least of which is Ember.js. I’ve never used a front end framework before. But I can see the power of it, plus, one of the key features of this new app is that it will provide a data api. With Ember.js, I believe, almost all interaction with the data will be through an api, so it seems like a good start and a way to sanity check what is coming in and out to other consumers of this api.

I know I suck at writing blog posts, but, I will try and document this journey because I have looked around and there doesn’t appear to be too many resources for people doing this. Everything I have found is much too simple and is not for the experienced Rails developer.

I did find one good resource from Tony Coconate (http://www.devmynd.com/blog/2013-3-rails-ember-js) and I am starting off from that. Now, that may or may not be a good idea!

Setup

I set up a new rails app. Then chucked some stuff into the Gemfile:
# front end
gem 'ember-rails'
gem 'ember-source'
gem 'ember-auth-rails'
gem 'ember-auth-source'

Create Resources

After, my first steps were to all but ignore the front end. 

I created my models as resources, like in Tony’s article. For example:

rails g resource Trainer name:string additional_info:text provider:references provider_key:string —no_helper

This means you end up with:
  • a controller, 
  • a model
  • a serializer - from active model serializer
  • a db migrate script 
  • two coffee script views (trainer and trainers)
  • entries in routes.rb
Moving Controllers

Again, as per Tony’s article, I am going to use Ember Data (whether or not it is ready for prime time now is not too important. This app won’t see the light of day for months yet). So, I move all the controllers from /app/controllers to /app/controllers/api/v1 and put Api::V1:: at the front. I also put in standard actions. So now my controller looks like this:

class Api::V1::TrainersController < ApplicationController
    respond_to :json

    def index
        respond_with Trainer.all
    end

    def show
        respond_with Trainer.find(params[:id])
    end
end

Modify Routes

I also modify routes.rb to look like this:

namespace :api do
    namespace :v1 do
        resources :trainers
    end
end

At this point I can point my browser at localhost:3000/api/v1/trainers.json and get a list (assuming I have data!) or to localhost:3000/api/v1/trainers/1.json to get the single record.

So far so good.

In my mind the data side of the app is on the way. I will not worry about any more Rails stuff for now.

Next is learning Ember.js 

Wednesday 25 September 2013

HTTP Basic authentication with Rails for iOS

Recently I've been getting into iOS and developing a interesting iOS app (more info coming soon!)

But, as the app is all about showing data of course I needed to create an API in my rails app to feed that data. But, I didn't want someone else to be able to grab it.

The Rails App Side

Configure a custom MIME type

First thing I did was set up a custom mime type in initializers/mime_types.rb:
Mime::Type.register_alias "text/json", :theapp
That let me call urls like /give_me_data.theapp

Add the 'respond_to'

In the applicable controllers add a respond_to (well, I already had one, so add to it):
respond_to :html, :xml, :theapp

Make templates with json_builder

I luuuvvvvv the json_builder gem. So I created a whack of templates with the .json_builder extension. Because of the mime type setting it would automatically get called.

Add the http_authentication stuff

I am a little bit lazy, so, I just chuck this into my application_controller. That means that all :theapp requests need authentication:

protected
def http_basic_authentication
    if request.format == :ios
        authenticate_or_request_with_http_basic do |username, password|
            username == 'myAmazingApp' && password == 'theBestestPasswordEver'
        end
    end
end

The iOS app side

The URLs

Simply chuck your authentication stuff into your urls:
NSString *const RegionDataBaseURL = @"http://myAmazingApp:theBestestPasswordEver@localhost:3000/regions/%@.theapp";

Pulling...Data

I do my stuff like this (thanks to Ray Wenderlich):
  dispatch_async(kBgQueue, ^{
    NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:RegionDataBaseURL, [self.region permalink]]];
    
    NSData* data = [NSData dataWithContentsOfURL: url];
    [self performSelectorOnMainThread:@selector(fetchedRegionData:)
                           withObject:data waitUntilDone:YES];
  });
Yes, I could also put the username and password in some other place and sub it into the URL, but brute force works for now.

Like I say, I am starting out in iOS so maybe this is too noddy for all you pros, but, it works.

Tuesday 24 September 2013

The gotcha's in Node.js - or how I reduced our bandwidth by 75%

So, I have this great application that distributes, in pretty close to real time, information across hundreds of screens in Germany. It does this with a combination of Rails, Node.js and HTML/Javascript.
But we noticed MASSIVE traffic.
My model was to pump out the data and have intelligent pages decide what to show.
It turns out this is very inefficient.

Not ready for primetime

We have 4 'channels' of information. The software had originally been built on a 'tv station' idea. And, in TV, everything gets pumped down the line (or over the air) and then the tv 'tunes in' to a channel and shows the appropriate content.
In our case, we had a 'screen structure' message that was sent out once a minute and then in between each element on the screen would send out its own updates if it was altered.
It was the screen structure message that was the problem.

The old way

I was doing something like this on the page:

client.subscribe('/source', function(message) {
    window.setTimeout(function() {
        process_source_message(message);
    }, 1);
})

And in Node app.js I was doing this:
app.post('/source_state', function(req, res) {
    bayeux.getClient().publish('/source', req.body);
    res.send(200);
});

And in Rails, something like this:
RestClient.post [NODE_CONFIG[Rails.env]['node_url'], NODE_CONFIG[Rails.env]['source_update_path']].join('/'), JSON(json)

So, every page would get every 'source' message.

The new way

I realised that I should have the pages listen to their specific channel. I had got hung up in the past on the idea that I didn't know the name of the source in advance - it could be anything as it is user defined.

But, inside of the source JSON was already this:
json = {
    "source" => {"name" => source.slug}
}

It turns out I didn't need to change the back end (Rails) at all.

In the app.js I just needed
app.post('/source_state', function(req, res) {
    bayeux.getClient().publish('/'+req.body.source.name, req.body);
    res.send(200);
});



Sunday 30 October 2011

installing sunport_rails on ubuntu production

We've added search functionality to Toygaroo with Solr via sunspot_rails.

If you are going to install it on Ubuntu then make sure you do:

sudo apt-get install openjdk-6-jdk

First!

Saturday 1 October 2011

Using the html5 boilerplate and rails 3

I am experimenting with using the html5 boilerplate with rails 3.0x. It is an interesting setup. I am using Russ Frisch's html5 boilerplate template, but updating it to use the latest boilerplate code.
It seems to be a pretty nice way of getting your css and js ducks in a row. Over the next few days I need to see how it handles having jquery mobile in the mix. I am also not 100% sure how to use a some sort of grid layout template (like 960 or 114opx) with it. Or even if you should!
We shall see.