Monday, February 1, 2016

Invitations (part 2)

Invitations (Part 2)

In Part 1 I left the project where I could have a user (the invitor) invite another user (the invitee) to have access to the "invitor's" posts. Additionally I could allow the "invitee" to change their email when they first singed up.

In Part 2 I finish up the discovery of using DeviseInvitable by accomplishing the following:

  • Fix some overlooked problems
  • Add ability to invite an existing user

Fix Problems

I realized after I finished Part 1, that the project I posted had a needless dependency on PostgreSQL.

My goal for this discussion was to better learn DeviseInvitable, not database setup. So I switched the database dependency back to the default "sqlite3" gem the "stock" rails app had when I first created it and updated the "database.yml" file.

To make this work, I also had to change the definitions for the "current_sign_in_ip" and "last_sign_in_ip" fields in the original User's migration as SQLite does not support PostgreSQL's proprietary "inet" data type. So these two lines (in {date}_devise_create_users.rb):

t.inet     :current_sign_in_ip
t.inet     :last_sign_in_ip

became:

t.string     :current_sign_in_ip
t.string     :last_sign_in_ip

The second problem I realized I had, was I had forgotten to limit posts by a user to only that user and their friends.

Without that "feature" it kind of defeated the purpose of the test app in the first place. So to fix that I added a "has_many" relationship to posts from the user.

I first created the migration and ran it:

rails g migration add_references_to_tasks user:references
rake db:migrate

I then added the requisite has_many :posts declaration to the User class and the belongs_to :user to the Post class.

Next, I had to add the following line to the PostsController#create method:

current_user.posts << @post

To ensure a user saw all their posts and those of their friends I changed the default implementation of the PostsController#index method to be this:

  def index
    # retrieve all posts created by me
    sql = "user_id = #{current_user.id}"

    # retrieve all posts created by my friends
    friend_ids = current_user.friends.ids
    friend_ids_string = friend_ids.join(", ")
    if (friend_ids_string.length > 0)
      sql = sql + " or user_id in (#{friend_ids_string})"
    end

    @posts = Post.where("#{sql}").order(:created_at)
  end

To be honest, at this point I thought I had the posts correctly restricted, which I did, but in testing I realized that when I created the friend_relationship in order for both sides to see the posts of the other I actually needed to create two friend_relationships. One for the user who just signed up and one for the user who did the inviting. I added that extra line of code to the User#add_friend method. I won't list that here, you can check the posted code out to see it.

With all that done a user can now login, create posts, invite a second user, and when that invitee sign's up they can create posts and both users can see the posts of each other as well as their own posts.

With that done I could now deal with my final question:

How can a user invite an existing user to see be their friend?

Inviting an existing user

The last question boils down to how can an existing user be invited?

The key to this question is to understand how DeviseInvitable handles inviting an existing user.

In that case no invitation token is generated or stored in the database and in fact all the code really needs to do is execute the code that would normally happen if a non existing user was invited and accepted the invitation.

To do this I changed PostsControler#invite to this:

  def invite
    @userToInvite = User.find_by(:email => params['email'])
    @invitations = current_user.invitations
    if (@userToInvite != nil)
      current_user.friend_relationships.create(:friend => @userToInvite)
      @userToInvite.friend_relationships.create(:friend => current_user)
    else
      @userToInvite = User.invite!({:email => params['email'], :skip_invitation => true}, current_user)
    end
    @userToInvite
  end

The change here is on lines 5 and 6. If we find the invitee already exists then we just set up the two friend relationships.

To test this, I started the app, signed up a new user, logged that user out, then logged in as the original user and invited the user I had just created.

When logged back in as the invited user they could now see the posts of their invitor.

At this point, I need to mention that this isn't how this feature will be implemented in the production app I am exploring this for.

In that app I will store off the fact the user was invited and possibly send them an email notifying them they were invited to be a friend. But, I will not automatically set up the relationship. Only if the invitee "acknowledges" the invitation will I actually create the relationships.

So that's it. All the questions I had have been answered. I now know how to:

  • Invite an outside user to the app
  • Collect other information when an invitee sign's up
  • Invite an existing user

You can view my first post on this subject here. I also updated the example project which can be found here.

Till next time.

Monday, January 18, 2016

Invitations (part 1)

I took a little break for the holidays but am back now. I view learning as more of a journey than a one time event. Therefore it is not enough to follow a tutorial to learn a technology.

Additionally as a professional developer, what I have found is that when I am trying to solve a problem I have to piece together multiple tutorials and examples from many different sources. With that said, I am going to try a new format for this post, where I will CLEARLY state the problem I am trying to solve and then write about how I went about (the journey) solving the problem. Here we go:

THE PROBLEM: From within my web app (as a signed in user) I need to be able to invite others to join me as users of the application. I would like the system to send an email automatically once I provide their email address, but for now if it just generates a URL, I could paste in an email, then that would be acceptable for now.

WHAT I EXPECT TO LEARN:

  • How to integrate invitations in authentication
  • A better understanding of devise

THE TECHNOLOGY STACK:

  • Ruby on Rails ver 4.0
  • PostgreSQL
  • Devise gem
  • DeviseInvitable gem

RESOURCES:

THE JOURNEY

I started by creating a new rails project called “devisetest”. My idea is to have users create posts only they can see. Then when they invite others, those others, (once signed up) can automatically see the posts of the user they were invited by. Subsequent users can invite existing users and those users would then be able to see those posts as well.

So I created a new test app:

rails new devisetest

Next I added the Devise and PostgreSQL gems to the Gemfile

gem 'pg'
gem 'devise'

I next installed Devise

rails generate devise:install

I followed the manual steps shown on the screen after rails installs Devise to ensure everything was setup correctly

I created a Post model and controller. A Post just consists of some text.

rails g scaffold post post_text:string

Added before action to PostsController.rb to make it secure

before_action :authenticated_user!

Updated database.yml for correct database connections, then created the database and ran the migrations

rake db:create
rake db:migrate

After running the migration I have two models, User and Post. User was created by installing Devise. The User object is used by Devise for authentication. See the Devise documentation if you want to use a different model.

Next I ran the server to test everything out

rails s

At this point I could sign-up a user and then login. I could add posts but I could not logout as a link to logout was not on my posts index page. I didn’t expect it to be there but I had to figure out how to add it.

To do that I added this to the posts/index.html.erb view

<%= link_to 'Signout', destroy_user_session_path, method: :delete %>

Now I can login, logout and create posts.

Next step was to add the DeviseInvitable gem to the Gemfile file.

gem 'devise_invitable'

Then run bundle install

bundle install

Next install devise_invitable

rails generate devise_invitable:install

Add devise_invitable to the User model

rails generate devise_invitable User

Run migrations

rake db:migrate

Finally, I copied the invitable views over as I think I will need to change them.

rails generate devise_invitable:views

Now the work begins.

The first question is how to generate an invite that I could email to someone. Since I don’t have ActionMailer set up, I will be happy with just generating the URL for now. I first looked at the routes that were now generated:

  accept_user_invitation GET    /users/invitation/accept(.:format) devise/invitations#edit
  remove_user_invitation GET    /users/invitation/remove(.:format) devise/invitations#destroy
     user_invitation POST   /users/invitation(.:format)        devise/invitations#create
 new_user_invitation GET    /users/invitation/new(.:format)    devise/invitations#new
                     PATCH  /users/invitation(.:format)        devise/invitations#update
                     PUT    /users/invitation(.:format)        devise/invitations#update

Looks like the “user_invitation” one is the most important at this point.

So how do I generate a invitation? I added these lines to my posts/index.html.erb file:

<%
user = User.invite!(:email => "new_user@example.com") do |u|
  u.skip_invitation = true
end
%>
Invite URL: <%= accept_user_invitation_url(:invitation_token => user.raw_invitation_token) %>

When I run this code I get the following on the web page:

Invite URL: http://localhost:3000/users/invitation/accept?invitation_token=P_JPFgFDY1w15y5pznSL

Looking in the database I see this record was created for a new user:

At this point I now know that invoking the User.invite! method creates the “user to invite” record in the database. Then either an email can be sent by the “invitable” gem or a link can be generated. Here I am calling accept_user_invitation_url to generate the link.

Either way this link is communicated to the user in some way. For an issue I will address shortly, it is important to note the User that was created in the database has an email attribute already set to the email that was used when the invite was created.

On the receiving end the user can use the URL and they will be taken to an “accept invite” form where they will be asked to set their password. Once that is done successfully then Devise will automatically log them into the system.

DeviseInvitable takes care of removing the User’s invite token after the user successfully sets their password (by submitting the form on the edit.html.erb view).

At this point I have several new questions:

  • How do I know who invited the new user?
  • How can I add other information when a new user accepts an invitation?
  • How could another user invite the same user to their posts as well?

How do I know who invited the new user?
To answer this question, I decided I needed to mimic how a real web app would work so I refactored the code by changing the code in posts/index.html.erb into a form that would collect the email address of the user to invite.

<%= form_tag("/invite_teammate", method:"post") do %>
<div class="field">
    <%= label_tag(:email, "Teammate Email:") %><br>
    <%= text_field_tag :email %>
</div>
<div class="actions">
    <%= submit_tag("Get Invite URL") %>
</div>
<% end %>

I created a named route to handle the form submission and placed it in my routes.rb file

 post 'invite_teammate', to:'posts#invite'

I added the implementation of the “invite” method in the posts_controller:

  def invite
   @newuser = User.invite!({:email => params['email'], :skip_invitation => true}, current_user)
   @newuser
  end

Finally I added the view ‘invite.html.erb’ to the views/posts directory:

<p id="notice"><%= notice %></p>
Invite URL: <%= accept_user_invitation_url(:invitation_token => @newuser.raw_invitation_token) %><br />
<%= link_to 'Signout', destroy_user_session_path, method: :delete %>
<%= link_to 'Back', posts_path %>

Notice in addition to showing the ‘accept invite’ URL, I also added ‘Back’ and ‘Signout’ actions so as to better use the test app.

The fix to my original question (how to know who did the inviting) was solved by passing the current_user field into the User.invite! method call in the posts_controller.invite method. But the refactoring will be helpful later.

On to my next question.

How can I add other information when a new user accepts an invitation?
The DeviseInvitable defaults to just asking the invited user for their password and confirmation password when they accept the invitation. But that really isn’t what I wanted, I really want the user to have the ability to use any email they have.

The start of the fix for this can be found in the “Configuring controllers” section of the DeviseInvitable documentation (see resources above).

To start, I needed to create a subclass of the InvitationsController. Since I was subclassing the User model it belongs in the app/controllers/users directory. (I had to create the users subdircectory)

Here is what it looks like:

class Users::InvitationsController < Devise::InvitationsController

  def update
    super
  end

  def edit 
    super
  end

  private 
  def accept_resource 
    resource = resource_class.accept_invitation!(update_resource_params)
    resource
  end
end

The ‘update’ method is the key here. It recieves the parameters from the edit.html.erb page when the ‘invited’ user uses the link they were provided. I overrode it here as I thought here is where I would accept the additional parameters.

I also overrode the ‘edit’ method as I thought I might need to add custom logic to it later. It is called when the ‘invited’ user navigates to the link provided and shows the form to collect their password information (and additional parameters we will see shortly).

The ‘accept_resource’ method is called when accepting invitations. Again I overrode this as I was thinking that I might need to add custom code here.

Next I overrode the default controller for invitations to point to my custom one in the routes.rb file:

  devise_for :users, :controllers => { 
    :invitations => 'users/invitations' 
  }

Finally, I needed to copy the default views for the devise_invitable’s invitations per the documentation:

rails generate devise_invitable:views users/invitations

This creates an ‘invitations’ and ‘mailer’ directory under views/users. There are two views under ‘invitations’, edit.html.erb and new.html.erb

I modified edit.html.erb to collect the ‘email’ attribute as well:

<h2><%= t 'devise.invitations.edit.header' %></h2>

<%= form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => { :method => :put } do |f| %>
  <%= devise_error_messages! %>
  <%= f.hidden_field :invitation_token %>

  <p><%= f.label :email %><br />
  <%= f.text_field :email %></p>

  <p><%= f.label :password %><br />
  <%= f.password_field :password %></p>

  <p><%= f.label :password_confirmation %><br />
  <%= f.password_field :password_confirmation %></p>

  <p><%= f.submit t("devise.invitations.edit.submit_button") %></p>
<% end %>

The default behaviour of the update method only allows the password and password_confirmation attributes, so to allow the email to be passed in (and updated) as well, we have to get past the strong parameters restriction on Rails. To do this I added a before_filter to application_controller.rb:

before_filter :configure_permitted_parameters, if: :devise_controller?

And the implementation of the new protected method ‘configure_permitted_parameters’ to allow the email parameter is:

def configure_permitted_parameters
    #Only add some parameters
    devise_parameter_sanitizer.for(:accept_invitation).concat [:email]
    #Override accepted parameters
    devise_parameter_sanitizer.for(:accept_invitation) do |u| 
      u.permit(:email, :password, :password_confirmation, :invitation_token)
    end
end

Now along with the password, the email is changed in the user’s record when the User record is updated.

The final question I have at this point, I will defer to the next post. You can see all the code here

Till next time.

Sunday, December 13, 2015

Embracing Reactive

I spent this week working on my webapp project.

For this project I had chosen to use ReactJS for the client side code. Additionally I was using a home-grown flux implementation for “gluing” the application together.

I was reading some general training material on Reactive programming and Flux and I realized my home-grown implementation might not have been as true to the Flux mindset as I originally thought.

So this week I explored whether to continue to use my existing implementation or choose one of the many pre-canned implementations.

For my implementation, I had three types of Actions, ServerActions, ResultActions, and ViewActions. I had one ActionCreator class that would create an Action object using one of these types and then that Action would be sent to my single Dispatcher class that would handle all actions.

Each Action had a type attribute that specified what action to take.

My Dispatcher class would inspect the Action type attribute and then directly call the appropriate method whether it be on my web service provider or a store directly.

This worked well but after reading more about general Reactive programming, I realized that although my intent was good I was probably not fully embracing the reactive style of programming and more particularly a “correct” Flux implementation.

This made me worry if I might hit a “maintenance wall” as my application grows.

In my mind, a “maintenance wall” is a situation in your code where you
made a design decision early on that later down the road you realize was a
poor decision. You are then left with a decision to either continue
using the incorrect design or refactor like a mad-man until you fix
it.

If you can avoid these poor decisions early it is a “win” for you future self. When using a new technology you are just learning, I believe, the way you “win” is by following the path and advice of more seasoned developers in that particular technology.

As you get more seasoned in that technology you build up a toolset and come to your own conclusions of how best to use the technology but until then you have to rely on the expertise of others. Sometimes those “experts” will lead you in the wrong direction, sometimes not, it just comes with the territory.

That was the situation I was facing.

The problems I saw with my current implementation was there was too much coupling between the Dispatcher and the Action handler code.

Additionally, my web service handler was directly calling methods on the various Store objects when it got results back from the server. Again another needless coupling.

In short, my implementation had a lot of coupling between classes. This seemed very much like an anti-pattern when using reactive programming. So I decided it was time to find a more “correct” design for my flux implementation.

I knew I didn’t need a whole sale replacement of what I had, just a slight course correction. I eventually ran across the ‘flux-rails-assets’ gem and decided this was what I was looking for. Or at least it was the start of what I needed

This gem provides a Dispatcher class and an EventEmitter class. You create one Dispatcher implementation and all your Stores are instances of the EventEmitter class and each one registers a single “action handler” callback function to the Dispatcher to listen for when Actions are sent.

This way ALL Stores “see” all Actions but only handle the ones they are interested in.

This is a lot better than my implementation as the code for handling actions and the Stores they affect are all collated together. A maintenance win.

Finally, components (think UI components) register with the Store instances to be notified when the Store changes.

Unfortunately, since all of my home-grown Flux code was written in CoffeeScript and the gem was not, it presented a bit of a challenge on how to integrate it.

Because of this I was not able to use the “extends” keyword from CoffeeScript to extend the EventEmitter class like I had hoped for. Well, at least I couldn’t figure out how to make it work.

If someone knows how please let me know as I don’t do a lot of
CoffeeScript in my day job so I may have missed a nuance of the
language that would allow me to do it.

So what I chose to do, was for each store I had, have it own an instance of an EventEmitter. So for my SessionStore the top part of the code looked like this:

root = exports ? this

class SessionStore
  loggedInProfile = null
  emitter = new EventEmitter

To allow components to be notified when the Store changes I wrapped calls to the emitter instance like so:

emit: (type) ->
  emitter.emit(type)

Then when a component registered with the Store for an event I would add that to the embedded emitter. Here is the add and remove listeners for a user’s profile in my SessionStore object:

addProfileUpdatedListener: (callback) ->
  emitter.addListener(Events.PROFILE_UPDATED, callback)

removeProfileUpdatedListener: (callback) ->
  emitter.removeListener(Events.PROFILE_UPDATED, callback)

The next big hurdle was how to attach a Store to the single AppDispatcher class supplied by flux-rails-assets. For each Store a action handler needs to be registered in the AppDispatcher.

The AppDispatcher will then call the action handler for each registered Store and each Store will do something with the actions it is interested in. The key point here is each Store gets every action.

The big issue I had here was how to attach the Store to the dispatcher. Here was the implementation for SessionStore I got to work after much trial and error.

root.SessionStore = new SessionStore

root.SessionStore.dispatchToken = AppDispatcher.register(SessionStore.handleAction)

The problem always revolved around the issue of what “this” was at the
time of the call

Now it was just a matter of wiring everything together. I will use the feature of the user updating their Profile as an example.

The SessionActionCreator for the update profile action looks like this:

updateProfile: (profile) ->
  action = 
    type: ServerActions.UPDATE_LOGGED_IN_PROFILE
    profile: profile
  AppDispatcher.dispatch(action)

This is called by a component when the profile needs to be updated.

In the SessionStore’s actionHandler method it handles the UPDATE_LOGGED_IN_PROFILE Action like this:

@handleAction: (action) ->
  type = action.type
  console.log("SessionStore is handling: "+ type)
  switch type
    when ServerActions.UPDATE_LOGGED_IN_PROFILE
      WebAPIUtils.updateProfile(action)

The updateProfile method in the WebAPIUtils class is called next and looks like this:

@updateProfile: (action) ->
  console.log("WebAPIUtils.updateProfile called")
  $.ajax({
    url: "/update_profile"
    dataType: 'json'
    type: 'PUT'
    data: { profile: action.profile }
    success: (data) ->
      SessionActionCreator.profileUpdated(data.profile)
    error: (xhr, status, err) ->
      console.error("/update_profile", status, err.toString())
   })

Notice the success handler funnels the result back through the SessionActionCreator. Here is the profileUpdated method:

profileUpdated: (profile) ->
  action = 
    type: ResultActions.LOGGED_IN_PROFILE_UPDATED
    profile: profile
  AppDispatcher.dispatch(action)

This gets passed back to the SessionStore via the AppDispatcher. Here is the relevant part of the actionHandler method:

  when ResultActions.LOGGED_IN_PROFILE_UPDATED
    SessionStore::setLoggedInProfile(action.profile)
    SessionStore::emit(Events.PROFILE_UPDATED)

This code updates the profile stored in the store and them emits the PROFILE_UPDATED event which registered components are listening to.

So now after making this slight course correction I have the following results.

  • All Actions are created by “action creator” class instances
  • The generated actions all go through the single AppDispatcher
  • All Stores see all Actions
  • There is a Store instance for each of the types of objects the app has
  • Components register with the various Stores for events they are interested in
  • Home-grown code has been removed

One thing that I don’t like is the registering of the component listening functions. In my old implementation a component would register using a key and a callback function. So when it was time to remove itself, it just used the key.

Now with this implementation I only use a function (because that is all the EventEmitter takes) so for a component to deregister it must pass the original function it registered with. I’m not sure why but that doesn’t feel right to me.

I will need to “noodle” on that one a bit.

Till next time.

Sunday, November 29, 2015

The Results

So last week I laid down the gauntlet that I was going to use this down week from work to rework Pain Logger to use the Realm database engine instead of CoreData and sync it all with CloudKit. Here are the results:

Monday

So I started looking at the existing code and I realized I needed to reorganize it a bit. In order to make it easy to manage and maintain, my idea was to create a single DataService class and have all persistence requests go through that.

The original Pain Logger code had a fairly standard CoreData stack being stood up in the AppDelegate (capturing the MOC on the way) and then it used helper classes for each of the managed objects. These helper classes isolated persistence logic away from the managed object instances and out of the AppDelegate. There was one managed object type per table and therefore one helper class per object type.

So my first order of business was to move all the helper methods and the CoreData stack initialization to the new DataService class.

I actually decided to concentrate on one UIViewController (VC) at a time, and move just the persistence methods it used. That way I could see progress.

After moving the methods for my first VC, I tested and found everything was still working.

The first VC just shows a list of the top level objects in my database so it wasn’t that hard.

Now I needed to install Realm. My idea was when the DataService stood up it would not only configure it’s existing CoreData stack, but it would also stand up the Realm database in order to migrate all the records.

I installed Realm for Swift 2.1 per the documentation Realm provides when you download their code.

I also installed the other tools, such as the Realm plugin for XCode and the Mac app Realm browser.

The only catch was after adding the “Run Script” (per Realm’s documentation) and trying a build, the build failed because the “strip-frameworks.sh” script didn’t have execute permission. So I opened up terminal and added execute permission to that file and all was good. Note: after you make this permission change, you next need to do a project clean so you won’t be using a cached version of the script.

My next hurdle was I needed to create Realm representations of the managed objects. So for example my Category class (which extends NSManagedObject) got a sister class called PLCategory (which extends Object).

Here was my first dilemma (and opportunity for improvement). CoreData doesn’t support enums, so all the enums in my data objects had to be converted back and forth between NSNumber objects. In Realm the answer to this is to overide the variable’s getter/setters. For example in the CoreData model assume you have this variable:

@NSManaged var line_color:NSNumber

I have an enum for this variable called LineColorType, so in the Realm object this becomes:

private dynamic var line_color = LineColorType.LINE_COLOR_GREEN.rawValue
var lineColor:LineColorType {
    get {
        return LineColorType(rawValue:line_color)!
    }
    set {
        line_color = newValue.rawValue
    }
}

The big change here is the application code will use the more standard camel case variables while Realm will store the raw value variables in it’s database.

My guess is I probably could have done this same thing with CoreData, but I’m not on that right now.

Delimma: There is a lot of boiler plate code left around to support CoreData and now adding Realm, although the new code is tighter, it is still MORE code. When do I get rid of the boiler plate code? I think the best approach is to finish all the changes and submit an update to the app store then after about 6 months (once I feel confident all existing users have upgraded and opened the app so the database has been migrated) I’ll remove the old CoreData code.

Day 1 Progress:
At the end of the day I have the model migrating to Realm. A good start I think. Tomorrow, I’ll start on the CRUD operations.

I ran into two issues for the day. First, how do I browse my Realm database. This StackOverflow link shows how to do that.
Second, my computed fields showed up in the database as well. It turned out I needed to mark them as non-persistent.

Delimma: Do I need a unique id on my objects? I decided I did, but I couldn’t just use an int because Realm currently doesn’t have an autoincrementing id scheme (it supposedly is coming). Anyway I choose to use NSUUID.UUIDString in the interum. We’ll see how that goes.

Tuesday

For today, my goal was to flesh out the persistence layer. My idea was to, along with the default Realm, set up a Realm for caching data when the user is offline, and a Realm to simulate the eventual online CloudKit support.

For testing purposes I plan to have a flag that I can turn on and off to simulate the app being in offline mode. Eventually this will be replaced by real code to check the availability.

As usually happens for plans like these, I ran into a snag.

I needed to add some test data, so I started using the app and realized there were parts of the UI that after the conversion to Swift didn’t functionally work, although they did compile.

It turns out I had used a automated conversion program to convert some of the original Objective-C code so that I didn’t have to type as much and it didn’t convert it as well as I would have liked.

So I spent most of the day fixing those issues.

By the end of the day I was able to add records as before, with them getting saved both to the CoreData database and the default Realm.

Wednesday

Today was a short day due to the preparations for the Thanksgiving holiday. My plan was to regroup and get more of the things I had planned to accomplish the previous day working.

One of the nagging issues I had was I feel the need to keep the old CoreData code active, while also adding the new Realm support. That way my existing ViewControllers can consume the old model objects until I am ready to make the transition to the new model objects. But this has turned out to be more problematic than I had hoped.

Another issue is parent-child relationships. In the existing code, when adding a new child, the child object would first be added to the database and then some updates were done on some computed values on the parent object and it would be saved.

This caused me to have multiple completion handlers that “chained” the updates. With Realm I can do all of that in one write transaction which is very helpful, but untangling the mess I created in the old code will take a bit of time.

Side note: Argghh! I’ve been “working” for about 3 hours and only got about 30 minutes of work in. I need to fill all these people up with tryptophan and me with caffeine. Unfortunately that won’t happen till tomorrow.

One thing that I don’t understand right now is should I cache the Realm’s I create? Are they expensive to stand up. Reading the documentation it feels like they are not. So to be thread safe right now I will make the Realm accessors in my DataService be computed attributes like this:

private var defaultRealm:Realm {
    get {
       return try! Realm()
    }
}

Is this a bad idea? I’m not sure.

Thursday - Thanksgiving

Not sure I will get much done today. Too much food, family and football!!

Friday - Saturday - Sunday

Well as expected, too much family time and not enough development time. I’ll have to continue this effort next week.

I didn’t quite make the goal I had originally started out to do, although now, I am much more comfortable with using Realm and I think this will be a very fruitful effort. I’ll make another post in a couple weeks to update my progress.

Till next time,

Sunday, November 22, 2015

The Plan

Well, I made it through last week’s annual run of Competition Manager, pretty much unscathed. The software worked flawlessly, however, as usual there were last minute requests for changes.

Competition Manager is a little different than other products, I have worked on, as (after the registration period closes out) it has to be rock solid for a frantic 24 hour period and then it is done until next year.

I always get requests for changes during that 24 hour period. It has always been my worst fear that a change request comes in that HAS to be implemented in the current run.

So far that has never happened and although I got another change request this year, we were able to work around the concern and put it off till next year’s competition. Whew!! another crisis averted.

So with that behind me for another year, I need to turn back to my mobile app, Pain Logger.

I completed the conversion to Swift about 2 weeks ago. Now it’s time to upgrade it.

Fortunately for me, the holidays provide time away from my day job and allow me to (while of course spending time with family and resting up) look closer at some of my side projects.

I read somewhere that to really be productive, you should state what you intend to do and your goal date so others can keep you accountable. So that is REAL goal of this post.

My Goal
My goal this week is to rewrite Pain Logger’s persistence layer to use the Realm database engine instead of Core Data. I intend to write it in such a way that an existing install will automatically migrate the existing CoreData database to Realm when the application launches and then on subsequent runs it will use the Realm database and not CoreData.

Once that is done I intend to stand up CloudKit support for the app. I intend to use Realm as the offline cache for the CloudKit database supporting the app.

So that is my plan, I intend to blog about my progress (which I hope to be complete) next week.

There, I now have placed the proverbial stake in the ground.

Now, why did I make the decision to go with Realm instead of using CoreData?

First, I wanted to learn something new.

Second, while CoreData works, I’ve always been put off by all the boiler plate code that needs to be done to stand a stack up, along with all the other moving parts you have to keep in mind as you are working with it. It has always felt so “2000s”ish to me. I want something more modern.

Realm seems to have that modern feel that I am looking for.

Having said all of that, I do, however, reserve the right to change my mind if this just turns out to be a really bad idea after getting into this.

So there you have it, until next time, here’s hoping for progress.

Sunday, November 8, 2015

Legacy Prawns

Ok, so I am coming to the close of my annual deployment of my Competition Manager application.

Right now registration is closed and the actual competition will happen this Friday.

In a way this is a bitter sweet time. In one way I am excited to see the culmination of my effort, but in another way it is a distraction to the other projects I am working on.

The project is a legacy app using Ruby on Rails version 3.2. I know I should update it to the latest version of Rails, but since it is not a paying project it’s hard to justify the effort.

At any rate, when the actual competition occurs this Friday, everything must work seemlessly, as the competition occurs over about 20 hours and all the scores and results must be collected, entered, calculated and reported on during that time.

This is the critical time for Competition Manager as there really is no time to fix any bugs if they were to arise.

So I was doing my due dilligence by testing the scoring and reporting modules of the application yesterday and I realized there was an annoyance for the scorekeepers I should try to address.

In the past after the scores for an event were entered, the user would save the scores and print the report. This caused a pdf file to be downloaded and shown in the browser.

Unfortunately this takes the scorer out of the application and forces them to save the report manually for later printing or print it right then.

I figured a better approach would be to download the file to the scorer’s computer as a separate pdf file without taking them out of the screen they were on. That way they could deal with all the reports at one time.

To do this I needed to do two things:
1. Give each event report a separate file name
2. Download the report instead of opening it in a separate browser window.

So this takes me to the crux of this post. My overall intent of these posts is to document things I learned or had to research to solve so that I, for one, won’t have to re-learn the issue again and maybe also in the process it will help others.

Competition Manager uses an older gem called “prawn” for it’s pdf generation and “prawnto” to support templates.

Yes I know there are better solutions and even “prawn” has a new version but one week out from the actual competition I am not about to change out a major component of the product.

So I had to figure out how to fix this with the current legacy code.

The way this works is I have a route set up to serve the reports that once called retrieves the correct data for the report then uses prawnto to load the template and generate the pdf. The original controller method looked like this:

   def event_results
       @event = Event.find(params[:event_id])
   end

So what would happen is the client would call this method with the event id and then the template named “event_results.pdf.prawn” would be used to generate the pdf file that was then returned to the client.

I knew I needed to set the filename and stream the file back to the client, setting the correct headers, but how to do it was hard to find. Here is what I eventually found that would work:

  def event_results
      @event = Event.find(params[:event_id])
      prawnto :filename => @event.name + ".pdf", :inline => false, :template => "event_results.pdf.prawn"
  end

So now what happens is the filename is set to the name of the event (with a .pdf extension), it is marked as inline false so the document will be downloaded, and finally the template to generate is specified.

So in the end a one line change solved the problem. I tested it, deployed it and the product is ready for action this Friday.

Till next time.

Sunday, November 1, 2015

Solving From A Different Direction

As of late I have been a bit remiss in getting these blog posts out the door.

Part of the issue has been I didn’t have a good blog creation solution. I have tried standalone apps, the provided editor from my blog provider and I even tried using different plugins to get the results I wanted.

This week I was documenting the REST API for my new web project and I realized that what I was doing there might solve the problem I was having here.

The problem has been how to show code snippets. So far all the standalone blogging apps I have tried have failed in one way or the other when I tried to attach code. In fact it was so bad that in my last post I had to post screen shots of the code.

That’s not right, so I have been hampered by this problem for a while.

As I said, I was documenting the REST API for my new web project and I have been doing it in Markdown so that I could view it, nicely formatted, from the git repository. In it, I had to show an example of the REST call in CoffeeScript as well as show the resulting JSON that was returned.

Markdown has a very simple way of showing code snippets, but for me it wasn’t working exactly right. It was delineating the code, like I wanted, but it was showing it all on one line.

What I learned, after some investigation, is Markdown has different flavors. Oh the joy of the open source world we live in ;-/

Anyway once I figured out the syntax for the particular flavor of Markdown my git repository supported I was able to get the code snippet formatted properly. So my CoffeeScript code looked like this.

     $.ajax({
        url: "/goals",
        dataType: 'json',
        type: 'POST',
        data: {
          goal: ...
        },
        success: function(data) {
          ...
        },
        error: function(xhr, status, err) {
          ...
        }

With this working it got me to thinking. What if I just wrote Markdown documents, and then exported them to HTML and pasted them into my blog? Would it work?

So today’s post is mostly a proof of concept of that. I can already see one downside and that is I’ll need to keep the Markdown versions locally, if I want to make any edits. It pretty much makes the editor on the blogging site useless.

I found several online editors that can take Markdown and export the HTML. Another requirement was that this HTML file had to be a single file, otherwise it would be hard to cut and paste it into the blog application.

After trying JavaScript, Swift and Ruby code I was pretty confident this could work. However, I also needed to show ReactJS code as well.

This has been the code that has presented the most challenge to the various solutions I have tried. The reason I think (I use JSX syntax) is the code starts out as JavaScript but then in the “render:” method turns into XML/HTML.

All this works because of the “JSX” compiler.

However, I have not found a standalone app that has handled this well. Admittedly I do need to go back and see what support the standalone apps have for Markdown, since I now think that is right format to use. At any rate, here is a simple JSX file:

var Page = React.createClass({
  getInitialState: function() {
    return {goals: []};
  },

  componentDidMount: function() {
  },

  render: function() {
    return (
        <div className="col-md-10 main defaultheight">Page
        </div>
    );
  }
});

I was pleasantly surprised how well this worked.

There is another advantage in using this scheme and that is any documentation I write for my iOS projects can also be done in Markdown (well a flavor of it).

So in the end the fix to a problem I was having for a different issue (that of documenting the REST API) may also solve the problem I have with including code snippets in blog posts. Anytime I can have one solution that solves two issues, I call that a win!

Till next time.