Sunday, March 27, 2016

Avoiding Massive VCs

One of my biggest beefs with iOS development has been the lack of best practices particularly when dealing with what code belongs in the ViewController.

For my development, I like to design with these goals in mind:

  • Each class/method has one responsibility
  • Functions should not have side effects.
  • Well understood functionality should be abstracted away into their own classes.

When writing UIViewControllers, however, I find it tough to adhere to these principles. The reason, I think, is the fact that because the UIViewController essentially is the code for a view in your app it takes on many responsibilities, such as manipulating the view's widgets, holding state for the widgets, setting values on the widgets, and responding to actions taken on a widget.

I see examples of this type of design all over the Internet. This munging of the responsibilities leads to what has been commonly called the "Massive View Controller" design pattern.

There has been a lot written about how to avoid this pattern and why it is a bad thing, so this post may not be very interesting to those who are well versed in this anti-pattern.

For me, though, I have come to a point in my rewrite of my app, Pain Logger, that patterns are starting to emerge to mitigate this issue that I can use for future apps so I thought I would write these up as minimum for my own reference in the future.

If this has provides any value to you I would love to hear about it.

Avoiding Massive View Controllers

To avoid the Massive View Controller problem I have began using four patterns:

  • View Models
  • Unidirectional data flow
  • Services
  • Protocols Extensions

Note: For this discussion when I say "view" I mean the UIViewController as seen on a storyboard along with it's actual UIViewController class representation. My goal is to reduce the code in these view controllers as much as possible to meet the goals I strive for as outlined above.

View Models

The intent of a view model is to hold state for the view. That way when a particular value needs to be displayed on the view, the view asks it's view model for the data rather than storing the data in the view itself. This allows the view model to do two things:

  1. Hold the data in it's raw format
  2. Transform the data into exactly what the view needs to display.

A simple example would be a date. The view model can hold the raw NSDate object and when the corresponding view needs to display the date it can ask the view model for correctly formatted date (i.e. a string).

With this pattern, business logic (in this case formatting of a NSDate into a String) is moved out of the view code and into the view model.

I started my rewrite of Pain Logger thinking I would move all the data manipulation to a view model class for each view controller. In the end that's not exactly how it ended up, but for this discussion I'll keep it simple.

When a view controller first stands up it creates it's corresponding view model.

var viewModel = VC_ViewModel()

Then in the view controller I wire up the widget's action to the control. But the IBAction implementation only updates the view model and calls the method to refresh the UI.

Here is an example where I wired up a UISwitch:

    @IBAction func handleSwitchChanged() {
        viewModel.showGraph = showGraphSwitch.on
        refreshUI()
    }

The refreshUI() method just reads the values from the viewModel and updates the view's controls appropriately. In this case setting the showGraph attribute to true causes another widget in the view to be shown.

This pattern works well for moving the view's state out of the view controller class. But as I worked through this I ran into another pattern that makes it that much more powerful. This pattern is called 'Unidirectional Data Flow'

Unidirectional Data Flow

Unidirectional Data Flow comes from the 'Reactive' world. I first ran into this pattern with my web work using ReactJS. In this pattern a change is made to data via execution of 'actions'. These 'actions' update a central 'store' which then notifies it's listeners that the store was changed.

There are many implementations of this pattern. The one that seems to be getting a lot of traction is the ReSwift project.

One of the problems I ran into with using the 'View Model' pattern was initialization of the state. But when I incorporated that with UDF, things began to clean up a bit.

Now there is a 'global' store that represents the state of the system at any moment in time. The view models no longer hold state for the view, they are responsible for isolating the business logic for formatting the data from the store into the appropriate format for the view.

For example, in Pain Logger, when editing a pain area, a title must be displayed on the view. The view model exposes a computed attribute for the view's title like so:

    var title:String {
        let name = categoryState.categoryName
        if (name.length > 0) {
            return name
        }
        if let cat = category{
            if (cat.isNew()) {
                return "New Pain Area"
            }
        }
        return "Unknown"
    }

In this example categoryState represents the store, so now the view model doesn't hold state, only the store does. When the refreshUI() method is called on the view controller (after being told by the store that it changed) the view model defers to the "store" to get the value of the system state and then provides the view with the correctly transformed data value.

It should be noted that by adding UDF to the design most if not all of the attributes on the view model become computed values. View models now hold no state either. You can see that in the code above where category is used. category is actually another computed value that looks to the store to find the category that is being edited.

Another consequence that occurs by adding UDF is the view controllers now listen to the store for changes, and actions from the view are dispatched to the UDF system rather than calling the refreshUI method directly.

So for example the handleSwitchChanged() method from above becomes:

    @IBAction func handleSwitchChanged() {
        mainStore.dispatch(SetCategoryShowOnGraphAction(showOnGraph:showOnGraphSwitch.on))
    }

In this way most IBAction methods become one liners, very cool.

Services

The next pattern is a little more mainstream. Using this pattern I moved all async operations out to specialized "service" classes. Each "service" uses the singleton pattern (for all of those who don't like this pattern, I still find it useful for this case). Because of the introduction of UDF the service's don't hold state. They just update the stores.

I have services for local and remote data among other things. Since storing to a database should be done off the UI thread I call the correct service for what I want to do. It modifies the database appropriately and updates the store with the changed values after they have been successfully persisted.

Since for the most part these services work asynchronously I can offload the work that needs to be done, then the UDF system kicks in when the response is received.

Protocol Extensions

The final pattern, that I am just getting used to, is protocol extensions. To be honest I didn't fully understand the value of them until I did some more studying of the subject.

I thought that protocols were just like interfaces from Java, and that would be right, until you throw in extensions. That's when things change, A LOT!!

Call me dense or whatever, but it seems to me that only when you start using protocol extensions do you start to get LOTS of reuse.

So the key to this is to define a behavior you want a class to have say like the title property from above. Since the view models don't hold state either I can define a HasTitle protocol like so:

protocol HasTitle {
    var title:String {get}
}

extension HasTitle {
    var title:String {
        let name = categoryState.categoryName
        if (name.length > 0) {
            return name
        }
        if let cat = category{
            if (cat.isNew()) {
                return "New Pain Area"
            }
        }
        return "Unknown"
    }
    
    var category:PLCategory? {
        get {
            return categoryState.selectedCategory
        }
    }
    
    var categoryState:CategoryState {
        get {
            return mainStore.appState.categoryState
        }
    }
}

Now any class can conform to this protocol just by adding it to the class's definition. Because the extension is defined, as well, there is nothing for the class (in this case a view model) to define and it "just gets" the behavior.

This is extremely powerful and I am excited about adding this new found knowledge to my code base.

Conclusion

So there you have it. A brief overview of some of the patterns I have found useful in architecting an iOS app and to avoid the Massive View Controller problem.

Till next time.

Sunday, February 21, 2016

How I learned Capistrano . . . 3

Capistrano3

With my current web app my goal over the past few weeks has been to get it to a stable state so I can just deal with scaling it out.

To do that, I needed to reduce the amount of time I was spending in deploying updates and I needed a repeatable set of steps that I couldn't mess up. That meant I needed to use an automated deployment tool. Since this is a Ruby on Rails (RoR) project, Capistrano seemed the obvoius answer.

I hadn't used it in several years but I thought it wouldn't be too hard to get back up to speed. It turned out that I felt like I was having to relearn it all over again.

So I thought I would write this post to document how I went about getting up to speed again. It turned out to not be that bad.

To start with I ensured I had the prerequisites in this tutorial completed.

Since I already had a running application, steps 1 through 4 (which consist of installing Nginx, PostgreSQL, RVM, Ruby, Rails and Bundler) were already completed.

All I really had to complete was Step 5: Setting up SSH Keys so the server could download from the git repository.

Next I searched the net for tutorials on installing and configuring Capistrano. I soon realized the tutorials were a mashup of versions 2 and 3. It wasn't always clear that the post or tutorial I was looking at was about version 3.

My take away at this point was this wasn't going to be a one afternoon effort.

Additionally, as I feared, each author was very opinionated about how it should be setup and configured. Needless to say, my comfort factor was not high for this endeavor.

So here is how I ended up regrouping and getting it done.

I started at the Capistrano website. Reading through the documentation, it felt like I wasn't getting the whole picture. The documentation is very consise.

Don't get me wrong, I think for someone who knows what they are doing the docs are great, but for me (and my level of expertise at the time) it was confusing. I like to know things like "Why would I want to do this" and "How does this fit into the bigger context of what I am trying to do" but there is little, if any, of that in the docs.

It felt like I wasn't making any progress. What I did learn, however, was the lay of the land for the documentation, the different components involved (even though I didn't know how they connected) and this first nugget:

Nugget 1: Capistrano 3 is based on Rake

One post I read recommended to first get familiar with how Rake tasks are built. This turned out to be a good idea. It gave me a better understanding about the code I was seeing in the Capistrano 3 config files. This was the recommended post and it is well worth reading all the way through.

It was a great start.

After reading that post I came back to the Capistrano documentation. I read more. Specifically I read these sections:

  • Installation
  • Structure
  • Configuration
  • Preparing Your Application
  • Cold Start
  • Before/After Hooks
  • Authentication & Authorisation

I also read the "Advanced Feature - Properties" section and then I looked at some of the plugins.

At this point I felt like I was ready to roll up my sleeves and get started.

A lot of the tutorials I ran across started with building the application and the server, and since I had already done that I won't go into those steps.

Installation

Capistrano installation was fairly straight forward, you just need to make sure you include the right gems. Since this is a RoR app, including the capistrano-rails gem was critical.

Nugget 2: Each gem adds to the list of Capistrano tasks you have available. You will need several of them.

Here is the list of gems I added to the Gemfile

gem 'capistrano'
gem 'capistrano-rails'
gem 'capistrano-bundler'
gem 'capistrano-rvm'

After installing the gems and running bundle update I then 'capified' the app:

bundle exec cap install

Having to do this seems to get glossed over in the Capistrano documentation.

I next added the require statements to the generated Capfile

require 'capistrano/rails'
require 'capistrano/rvm'

Note: To start with I purposefully did not add the nginx or unicorn capistrano gems so I could just concentrate on getting the app to install properly. I also chose to deploy the app to a test directory on the production server so I could compare it to the running application to know that it was working correctly.

At this point I could run cap -T to see the list of available tasks.

Configuration - Deploying the Code

Next, most of the tutorials, will take you into configuring the deploy.rb and production.rb files that got laid down when you 'capified' the app.

The documentation in both of these files is pretty good, but the problem was, at least for me, it was overwhelming. What EXACTLY did I need to set up to get going.

Nugget 3: config/deploy.rb is for common settings and configuration, config/deploy/production.rb is for settings specific to your production deployment and config/deploy/staging.rb is for settings for your staging environment (i.e. a pre-production/test environment). The settings in depoy.rb will be overridden by settings in production.rb or staging.rb depending on what you are deploying.

Next I wrote down the steps I would have to do if I was deploying by hand. These were the steps I wanted my Capistrano deploy setup to do. The steps I needed to accomplish were:

  1. Run local tests
  2. Stop nginx
  3. Update the code
  4. Run Bundle install (if needed)
  5. Run rake db:migrate (if needed)
  6. Compile assets
  7. Link shared folders and files
  8. Restart nginx
  9. Restart unicorn

Knowing what I needed to do helped me figure out what settings I needed to set.

Here are the config settings I ended up with in the config/deploy.rb Note: anything listed in {} needs to be changed to match the server environment being run in.

set :application, '{my_app_name}'
set :deploy_user, '{deploy}'
set :scm, :git
set :repo_url, '{git@...}'
set :deploy_to, '{/home/deploy}'
set :format, :pretty
set :linked_files, %w{config/database.yml}
set :linked_dirs,  %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
set :keep_releases, 5
set :keep_assets, 2
set :tests [{a list of path+file names to the spec tests to run}]

Next I moved to the 'config/deploy/production.rb' file and set these attributes:

set :stage, :production
set :branch, 'master'
set :server_name, '{my server name}'
server '{my server name}', user: '{deploy}', roles: %w{web app db}, primary: true

set :rails_env, :production

set :ssh_options, {
    forward_agent: true,
    auth_methods: %w(password),
    user: '{deploy}'
}

I was finally ready to run the first deploy

cap production deploy

As expected it didn't work, but it was close.

There were some deprecation warnings I needed to fix, I found it was best just to look at the log and fix the issues.

The next problem I encountered was the deployment could not link to the 'database.yml' file from the shared directory. I expected this so I logged into the production server and put the file in place. Note: Capistrano has the ability to create/install the application on a new server. I chose not to go this route for this deployment as all the config files for nginx and unicorn were already in place.

Nugget 4: Review the capistrano output. It is important to fix as many problems as you see in the capistrano output. Some commands that are marked "failed" are ok as some directories may not exist in your project. You can use cap production deply --dry-run if you want to do a trial run of the deployment without actually doing it. This is good for when you make a large or potentially destructive change.

Basically you want to put anything that you can share between projects into the shared directory and symlink them over. One extra one I had to do was a hidden folder for my ssl certificates.

Once I cleaned as many issues up as I could, without doing any custom tasks I had items 3 through 7 working. Now on to the server stuff.

Installation - Controlling the Application Server

I first started by adding the nginx and unicorn gems to the Gemfile:

gem 'capistrano3-nginx'
gem 'capistrano3-unicorn'

I required both in the Capfile:

require 'capistrano/nginx
require 'capistrano3/unicorn' 

I also added the correct deploy steps to the deploy.rb file:

before :deploy, 'nginx:stop'
after 'deploy:publishing', 'deploy:restart'
task :restart do
  invoke 'nginx:restart'
  invoke 'unicorn:reload'
end    

At this point I started getting "sudo: no tty present and no askpass program specified" I fixed this by adding the NOPASSWD option to my deployers group on the server.

sudo visudo

#add this line to bottom of file
deployers ALL=(ALL) NOPASSWD: ALL

This allowed the Nginx service to be controlled by the deployer account.

At this point steps 2, 8 and 9 were complete on my list.

Installation - Running Tests Before Deployment

The final thing to complete was getting the tests running on the local development box prior to allowing the deploy to the server to happen.

To do this I created a custom task named run_tests.cap and placed it in the lib/capistrano/tasks directory. Here is it's contents:

namespace :deploy do
  desc "Runs test before deploying, can't deploy unless they pass"
  task :run_tests do
    test_log = "log/capistrano.test.log"
    tests = fetch(:tests)
    tests.each do |test|
      puts "--> Running tests: '#{test}', please wait ..."
      unless system "bundle exec rspec #{test} > #{test_log} 2>&1"
        puts "--> Tests: '#{test}' failed. Results in: #{test_log} and below:"
        system "cat #{test_log}"
        exit;
      end
      puts "--> '#{test}' passed"
    end
    puts "--> All tests passed"
    system "rm #{test_log}"
  end
end

I got this from a post I read. It should be fairly explanitory. It essentially fetches the tests from the array of tests I added to the deploy.rb file and runs them. If any test fails the deployment is halted.

To bring this custom task in I added these lines to the bottom of the Capfile:

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
Dir.glob('lib/capistrano/**/*.rb').each { |r| import r }   

I am probably including way many more types of files than I should but it does cover all the bases so I went for it.

Finally I added this line to the deploy.rb file:

before :deploy, 'deploy:run_tests'     

I reran cap production deploy and all was good.

Of course this post glosses over many of the stops, starts, restarts that I did to get this to work. I bet I deployed the app more than 50 times before I got it all right.

Here are some other issues I ran into along the way:

I ran into a problem where on the production server the Gemfile.lock was out of sync with the actual gems I had installed. I tried to run bundle install on the server but it would fail until I moved into a real directory and not by running it in the current directory. It seems the symlink messed that up.

Another thing that bothered me was all the "failures" the Capistrano log showed while deploying. I found this post where the comment by bruno at the bottom on Nov 6 will give you some comfort. At least it did for me.

Another thing that was still very opaque to me was what tasks were really being run and what did they do? There was really no documentation I could find on that. The only way I got a clue of what was going on was looking at the source. That was pretty enlightening, but not for the faint of heart.

One other thing I learned, if you change the ":format" setting to ":dot" instead of ":pretty" you will see red and green dots as the deployment script runs instead of all the verbose output. This makes it "feel" better at least. Only do this once you know everything is working though.

Final Thoughts

It was a long process to get this going. I spent many hours 'googling' and reading posts to come up with this configuration. Was it worth it? I think so. I can reliably deploy the app in about 2 minutes all from my dev box. As a side affect I also can run tasks like nginx:restart at any time I want to which will help out in day-to-day server management.

I guess my next steps in this area is to better understand what the tasks are that are run, and configure the deployment so I could actually install the app with Capistrano on a new server. But that will have to wait for another day. It's time to get back to coding.

Till next time

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.