How Making it Work Means Using Defaults

I found a cool project that effortlessly sets up Google Hangouts in your app, Instant Hangouts. You can create a custom room and topic title and invite your users to talk to each other. The only problem was a persistent 400 error, preventing me from knowing whether the repo was a work in progress or whether it really worked!

Luckily, John Cox the project’s author graciously included his contact details and replied to my emails. Eventually, he suggested the obvious: use node.js ( what the repo was written in ) rather than Rails, the context where it would be useful to me.

In just 5 minutes, I got the repo working in node, and from there, I copy-and-pasted my way to wild success.

The moral of the story: look before you leap! In order to make it work, make it right, and make it fast, sometimes you need to step outside of your comfort zone (using node) to properly stand on the shoulders of giants.

The Logic of Parsing Excel Files

Advertisers put their content in the medium that their marketing targets use i.e. advertise on Facebook if your customers use Facebook. However, when I act as the medium between knowledge experts and a web app that delivers that expertise to users, I want those experts to collborate with me using a platform they already know. In the case of inputing data, I ask them to use an Excel sheet, and I use the Ruby gem “Roo” to get that info into a database.

Ruby Basics of Roo

Using Roo is simple:

  1. gem install roo
  2. require ‘roo’
  3. s = Roo::Excelx.new(“myspreadsheet.xlsx”)
  4. s.default_sheet = s.sheets.first
  5. define your attributes by column
  6. iterate through each row of your excel sheet, with a starting and ending row
1
2
3
4
5
6
7
8
9
10
11
12
13
start_row = 3
end_row   = 78

(start_row..end_row).each do |line|
  attr_one   = oo.cell(line, 'C')
  attr_two   = oo.cell(line, 'D')
  attr_three = oo.cell(line, 'E')
  attr_four  = oo.cell(line, 'F')
  attr_five  = oo.cell(line, 'G')

  object     = Object.create(:attr_one => attr_one, :attr_two => :attr_two)
  detail     = object.details.create(:attr_three => attr_three, :attr_four => attr_four, :attr_five => attr_five)
end

Other Ways of Using Roo

You can create a checklist system where Excel rows are filled with an “x” if an entry meets a column criteria. For example, if you’re tracking how many continents you’ve visited, you can put an “x” under each continent visited (such that columns B-H are Europe, Arica, etc.). You can also define your own ruby methods to transform the excel data as needed.

Roo is a simple but powerful tool for collborating with knowledge experts to build a powerful web app. Find more information at its Github to parse things like CSV and OpenOffice.

The Goal

You’re making a form with 2 selectboxes: based on the user’s selection in the first box, the second box updates. A possible use is an interactive menu with a selectbox (drink, appetizer, dessert), and a second selectbox that updates (coffee, juice, tea — if you select drink).

How do we write the HTML, Ruby, CSS, and Javascript to make it work?

HTML & Javascript Overview

Use the .change() jQuery method as the event listener for the first selectbox. Based on the name attribute of option selected, use CSS to reveal the correct set of 2nd-selectbox options.

I created a .hide {display: none;} CSS rule and applied it to all 2nd-selectbox options. For these same selectboxes, I gave them the same ID as the name attribute of the matching option of the first selectbox.

Furthermore, I used Ruby and ERB to grab “Subjects” and “Details” from my database. In the code below, Detail belongs_to :subject, and Subject has_many :details.

See the Javascript and HTML code below:

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<h3>Pick your subject:</h3>

<select id="first-selectbox">
  <option value="" name="select-one">Select One</option>
<% Subject.list.each do |subject| %>
  <option value=<%= cssable(subject) %> name="<%= cssable(subject) %>"><%= subject.titleize %></option>
<% end %>
</select>

<h3>Pick your detail:</h3>

<select class="show" id="no-details">
  <option value="">Select One</option>
</select>

<% @subjects.each do |subject| %>
  <select class="hide" id="<%= cssable(subject.title) %>">
    <option value="">Select One</option>
  <% subject.detail_list.each do |detail| %>
    <option value="<%= detail %>">
      <%= detail.titleize %>
    </option>
  <% end %>
  </select>
<% end %>

Javascript

1
2
3
4
5
6
7
8
9
10
11
jQuery(function(){
  $( "#first-selectbox" ).change(function() {
    var detail_id = ( "#" + $( "#first-selectbox option:selected").attr('name').toLowerCase() );
    $( ".show").addClass("hide");
    $( detail_id ).removeClass("hide").addClass("show");
    
    if (detail_id === "#select-one") {
      $( "#no-details" ).removeClass("hide").addClass("show");
    }
  });
});

Cross the Ts: Getting the Ruby and HTML Details Right

As you can see, the actual code is a lot more complex than the overview. This is because:

  1. I made a default selectbox for the 2nd selectbox, which requires some fandangaling to handle because it falls outside of the “subject equals 2nd selectbox id” pattern.
  2. I created my own methods (subject.detail_list and Subject.list) to return a list of associated subjects and details, to avoid making unnecessary queries to the database.
  3. I created a view helper cssable(string) to make subjects longer than one word, like “Main Course,” separated by dashes, like “main-course,” so that the value could be captured in HTML.

Conclusion

Updating selectbox selections is a straightforward concept that nonetheless requires some attention to detail to get working perfectly. My approach was to get the basic concept working (as can be found in this JS Fiddle), then to make it work in my actual application.

The recent ArtsEdTech meetup is the best Meetup I’ve attended for one reason, and one reason only. Do take my opinion with a grain of salt – I’m a newcomer to the Meetup scene, and this meetup’s theme fits my background perfectly: my dad and brother are graphics designers, I used to be an edu-policy analyst, and now I’m a Ruby on Rails developer. But what made the ArtsEdTech meetup so darn special was the quality of the connections made at the event.

My first conversation was 90 minutes long, with the people I happened to meet on the elevator. One guy works for 4.0 Schools. Another is a SPED expert, and the other works for Amplify. Together, we shared perspective that was heartfelt, genuine, and slightly radical. We came to ArtsEdTech because we’re upset with education. But we also share a common belief that Ed-tech needs more heart, and the Arts need inclusion. Not exactly a radical stance, but when you talk to educators who are confronted by this reality everyday – how old ways of doing things prevail over exploration and experimentation – you wonder what keeps the current system place if nobody likes it.

However, at least two people boldy broadcast how education needs both heart and mind: Sam Blanco and Jessica Wilt. These two educators deeply inspired me: Sam for organizing and hacking learning resources for SPED, and Jessica for identifying the need for and bringing together ArtsEdTechNYC. Because I love their work, I’m Gittiping them both a nominal amount to show my support. Please check out Sam’s website or attend the next ArtsEdTech meetup.

If you’ve just gotten really excited and marked your calendar for the next ArtsEdTech meetup, then here’s my advice on how to get the most out of the experience:

  1. Bring a pet idea for how you would change education and share it with others. You’ll be pleasantly surprised by the positive reception and critical insight you receive.

  2. Share your expertise with others. You know something that others don’t. Share it and everyone benefits.

  3. Be passionate. Believe that people who come together with a common belief can make a difference. We’re doing this for the kids, really.

By the way, if you’re a developer or know developer friends, I’m the only attendee that I met who described themselves as a programmer. There’s a huge opportunity for collaboration between passion-bleeding educators and do-gooder coders. If you can, make it happen.

Pedagogy Gap is a free online survey that helps teachers make learning more relevant for their middle and high school kids. It’s the product of my undergrad thesis, a year’s worth of research and writing. I’m excited to see if students or teachers will find it interesting. For now though, I’ll discuss the technology behind the site.

  1. Ruby on Rails

    A popular web framework that’s intuitive and powerful. Because the site has many models and persists data in a database, I decided not to go with Sinatra, which is a smaller web framework.

  2. HighCharts

    A popular Javascript plugin that graphs data. It’s easy to work with and beautiful too. By making my graphs render as partials, I could dynamically generate different sets of data with just a few javascript files. For example, I have 3 Highcharts javascript files generate 18 different graphs.

  3. Flat-ui

    It’s a free and elegant theme.

  4. Anonymous Students

    I wanted students to take the survey without having an email address, but also without using an awkwardly long and hard-to-remember token. So I made students a separate model from users who require authentication. Instead, teachers give students a passcode that allows them to create a student.

    So while this lowers barriers to using the survey, because teachers do not have to collect their students’ email addresses to send them the survey, this creates the concern that students could take multiple surveys.

    In the future, I will add features that make this situation more secure; however, I wanted this survey to be as easy to take as possible. Another benefit is that students can initiate the survey without having their entire class’ emails.

Please take a look at www.pedagogygap.com. You can sign in with pre-populated survey results using these credentials: [{email: curious@curious.com, password: curious}, {survey_id: 15, survey_password: curious}]. Let me know what you think @surrealdetectiv.

I’d like to make a Tic Tac Chec program, so to begin, I wanted to be able to move a rook around the board.

The Setup

To better understand the mechanics of the program, I decided to make a command line program in Ruby. I put each Class into a separate file, then used require_relative to include them into an app.rb file. I also required the PrettyPrint class to beautify my output.

There is a Game class, which initializes with @player1, @player2, @board, and sets the first turn to be played by Player 1. During their turn, Player 1 chooses which piece to move based on its x-y coordinates. Then the player chooses where to move the piece based on a list of possible moves. Next, it’s the other player’s turn to move a piece.

I created an 8x8 board with 4 rooks on it, two belonging to each player. It started like this:

1
2
3
4
5
6
7
8
9
 coordinates x/y: 0    1    2        3    4    5        6    7
             0  [nil, nil, nil,     nil, nil, nil,     nil, nil],
             1  [nil, nil, nil,     nil, nil, nil,     nil, nil],
             2  [nil, nil, P1-Rook, nil, nil, nil,     nil, nil],
             3  [nil, nil, nil,     nil, nil, nil,     nil, nil],
             4  [nil, nil, P1-Rook, nil, nil, P2-Rook, nil, nil],
             5  [nil, nil, nil,     nil, nil, nil,     nil, nil],
             6  [nil, nil, nil,     nil, nil, nil,     nil, nil],
             7  [nil, nil, P2-Rook, nil, nil, nil,     nil, nil]

Finding the Rook’s Available Moves

Upon selecting a piece, the player receives a list of x-y coordinates where that piece can move. I defined the method available moves in the Rook class.

1
2
3
4
5
6
7
8
9
class Rook < Piece
  def available_moves x, y
    horz_left x, y
    horz_right x, y
    vert_up x, y
    vert_down x, y
    moves
  end
end

The method returns a list of moves after checking each direction for open squares. Based on the rook’s position, these “by direction” methods find whether there is a piece obstructing the rook’s path or else adds that x-y coordinate to a list of moves. See below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Rook < Piece
  def horz_right x, y
    ((x+1)..7).each do |x_pos|
      square_or_piece = self.player.choose(x_pos,y)
      return if add_by_x_pos(square_or_piece, x_pos, y) == "stop"
    end
  end

  def add_by_x_pos square_piece, x_pos, y
    if square_piece.nil?
      moves << [x_pos, y]
    else
      add_taking(x_pos, y) if square_piece.player != self.player
      return "stop"
    end
  end

  def add_taking x, y
    taking_moves << [x, y]
    moves        << [x, y]
  end
end

The first method checks all squares to the right of the rook until it finds a square with a piece in it. Then, the second method determines whether the rook can move there based on whether this piece belongs to current player. If it’s an enemy piece, the third method adds that square to both the move list and the taking_moves list.

Once a piece is found in the Rook’s path, the second method terminates itself with a return "stop" that then stops the first method. This way, only spots that need to be checked are looked at.

Takeaways and Future Improvements

As I was coding this, I also wrote the logic to switch turns between players. While my initial focus was getting rooks to move properly, it was necessary to associate rooks with players if I wanted to determine if a rook could move into another piece’s square. Therefore I ended up building the game class despite not intending to do so immediately.

Luckily, I already had a good idea of how to design the chess app in general. Rather than just starting anywhere, having a sense of how the entire program is designed proved to be invaluable.

In the future, I will add the logic for more pieces and create a way to recognize when the game is finished. Stay tuned!

To stop a div from taking the wrong spot, use these 3 standard CSS tricks to stay in control.

Clearfix for Pro Positioning

Sometimes you want your parent div to have a height, but it collapses to zero height when its children div float left. To give it a height, use the clearfix solution (note that clearfix is used for block elements, and not inline-block elements, which requires other fixes if you want to use it).

1
2
3
4
5
6
7
8
.clearfix:after {
  content: ".";       //adds content
  display: block;     //block display makes it 100% of the width
  clear: both;        //clear puts the period below the divs children
  visibility: hidden;
  height: 0;          //bc height is 0, the div's height is set to the max height of its children
  line-height: 0;
}

A parent div collapses because its height is determined its contents, but floating its children divs effectively makes it empty. The clearfix class is a signal to the parent div that it is not empty. It accomplishes this feat by actually adding html content, in this case, a period, which acts as a ruler for the parent div letting it know how tall its chidlren are.

Clearfix Exercise

Make four divs: one parent div, and three children div as its contents. Give the 3 children div a height and width, then float them left. Verify that the parent div has collaspsed to a height of zero. Finally, give the parent div a clearfix class to give it a height.

Wrapper for Simple Centering

It’s common to limit the width of where your main site’s content appears. Furthermore, you want that container for your text to be centered within its parent div, the most common case being the browser window. By implementing a wrapper class, you can arbitrarily make any div centered within its parent div by surrounding it with a div with the wrapper class.

1
2
3
4
5
.wrapper {

  margin: 0 auto;

}

This works by setting the left and right margins to be automatically set by the browser as equal, which centers that div’s contents, as long at they are also block elements. If you want to center the text of an element, use text-align: center;.

Overflow for Stabilizing Div Areas

When text is generated dynamically, such as a user-written bio written on her profile, your design could require its containing div to be less than a specific height. But if a user writes a very long bio, that text content would break out of your div and compromise your design.

One solution is to simply limit the amount of text that a person can enter into the bio. Another is to limit the number of characters that can be displayed in the view. The third solution involves the overflow css property.

1
overflow: auto;

Overflow auto generates a side scroll in your div when its contents are larger than the div’s desired size. You can also use overflow: hidden; to stop oversized contents from being displayed outside of its container div.

Wrapper Overflow Exercise

Create a div with a fixed width and height. Give it contents that go outside the div. Then use the overlfow property to keep the contents inside the div. Next, give that div a wrapper class with a css rule margin: 0 auto;.

Good luck!

Javascript Basics: Variables, Functions, and Scopes //plus comments!

First Experience

I’m learning Javascript after learning Ruby. Below are my notes from http://jqfundamentals.com/chapter/javascript-basics. Feel free to follow along!

My First Original Function

1
2
3
4
5
6
7
var explanation = function(name, message) {
  var exclamation = 'But ' + name + ', ';
  log( exclamation + ' ' + message);
};

explanation('Jerry', "I was over the rainbow");
explanation('Jasmine', "I wanted some tea.");

3 Lessons:

  1. Define a variable using var variable_name =
  2. A function takes parameters that you can use inside that function
  3. All variable assignments or methods end with a ;

1 Minute Assignment:

Write an original function using the basic pattern above.

Comments

  1. // is used to make a comment
  2. /* is used to begin a multi-line comment
  3. */ is used to end a multi-line comment

Variables

  1. Variables do not begin with a number or hyphen
  2. Functions can only be called when defined as a variable
  3. Define a function as a variable using var or function
1
2
3
4
5
6
7
8
function myage(a, b, declaration) {
  function age(a, b) {
    return a*b;
  }
  log( declaration + ' ' + age(5, 5) + ' years old.')
}

myage(5, 5, 'I am');

2 Takeaways:

  1. For functions within a function, the nested functions should use the parameters provided in the outer functions and not introduce new parameters.
  2. “Function Expressions” begin with a var, and are superior to “function declarations” because the former they are more predictable and can be used in larger scopes. See http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/ for more detail.

1 Minute Assignment:

Write a function inside a function like above and successfully call it.

Return Value

  1. Use return to perform math
  2. Wrap a command in the log(); method to print the return value in the console
  3. There can be no return values after errors.
1
2
3
4
5
6
7
8
9
var myFunction = function() {
  var foo = 'bar';
  return foo
};

log(myFunction());
log( typeof foo );
hilarious;
log(myFunction());

Above, the return values are bar and undefined. The command hilarious; is not defined and also breaks the Javascript, preventing it from reprinting bar.

If you’re not using a dynamic editor, use console.log() to print Javascript into your browser’s console.

Scope

  • Functions create a scope wherein variables defined within are not acknowledged wihtout. This is why log( typeof foo) returns undefined, because foo is undefined outside of myFunction.

    It’s worth noting that the same function without ‘return’ will return undefined because it is outside scope.

1
2
3
4
var myFunction = function() {
  var foo = 'bar';
  foo
};
  • Because of variable scope, you can have different variables that share the same name, but exist in different scopes.
1
2
3
4
5
6
7
var foo = 'qux';
var myFunction = function() {
  var foo = 'bar';
}
log(foo); //returns 'qux'
myFunction(); //does it redefine foo as 'bar'?
log(foo); //nope, still returns 'qux'
  • Therefore it’s best to name variables uniquely and descriptively to avoid confusion between scopes.

  • Generally, use var to assign all variables because otherwise, the variable you define will default to a global scope.

1
2
3
4
5
6
7
function test() {
  a = 1;
}

test();

log( a ); // logs 1

Don’t do the above because if you set the variable a in other places in your code, there will be conflict.

To solidfy your understanding, try the following exercise:

Culminating Exercise

Build an “ATM” using only javascript. Create a file called atm.html and insert your code within two script tags. Your ATM should tell you what your starting balance is and allow you to deposit, withdraw, and exit the ATM. Assuming that you’re new to Javascript, aim for a minimal ATM program in 45 minutes.

Try the following methods in your browser’s console, as they will prove very useful. Good luck!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
  //interact with the user
  alert('your message');    //sends a one-way message to user
  prompt('your message');   //returns user input 

  //such as:
  var name = prompt('What is your name?');

  //interpret user input
  isNaN('seventeen'); // evaluates to true or false
  parseInt("17");     // =>17 

  //perform actions based on conditions
  if (condition) {
    someMethod();
  } else if (condition) {
    someMethod();
  }

  //conditions
  name === 'Alex' // evaluates to true or false

</script>

This picture changed the way I saw the world for a day.

After programming for 9 weeks at Flatiron School, I picked up a book on visual design. It explains design concepts like professors who, at first glance, delve into gratuitous detail… until you realize how that info germinates your understanding. Better yet, the book offers useful steps for UI beginners to improve their designs intuitively. (And the book comes in green)

Here are 3 tips I used from the book to…

improve my UI design.

1. Reduce

Identify the functionality of a given thing, then eliminate unessential clutter. The books says wisely,

“Whereas art strives to express fundamental ideas and perspectives on the human condition, design is concerned with finding the representation best suited to the communication of some specific information” (Mullet 9).

In other words, design serves a purpose, so the fundamental principle of good design is to know its own purpose. Just as how a ruby method shouldn’t do too many things, the same applies to design – too many features will limit its usefulness.

2. Balance by Rank

Chunk and label the elements of your design into named groups, then destablish a clear visual hierachy. This means ranking your named groups in order of importance from 1-7. In your design, the one or two most important elements must stand out, with others reduced to supporting roles. The process of ranking your design elements will give your creation process a purpose, as it will clarify what your design should achieve.

Adjust the size and value of elements to make them stand out. In general, maximize perception difference between groups, but minimize them within like-objects.

3. Regularize

Use a meaningful pattern to achieve a design’s purpose by repeating similar elements. As a design beginner, my approach towards finding a meaningful pattern is to solve easier problems first. Then, if I can use those simple problem-solving patterns to also solve more complex ones, then that constitutes a meaningful pattern.

Another approach is to look for repeated functionality within your app, find its simplest use case, then re-purpose it to more complex use cases.

Case Study to Re-design UI

For my team project at the Flatiron School, we’re creating a website that helps Flatiron School process applicants to its classes. One of the views in the website lets the administrator search for applicants. Before, we had 5 columns and as many as 5 lines within a cell. The view bewildered users.

To improve the design, I first focused on what the page hoped to achieve – find applicants. More specifically, the administrator searches for applicants to then take a look at their entire application. Everything else should be eliminated or de-emphasized. Ultimately, this is what was left:

I then re-used this basic design for another view where the administrator is skimming through initial applications before reading the entire thing.

By using a familiar pattern, the app can utilize space more effectively. In this case, it can fit many actions into a relatively small space because the user has become accustomed to part of the view.

Designing UI Takeaway

By identifying the purpose of a design and communicating that purpose in a simple and elegant way, you can greatly improve your UI.

Addendum

After seeing the picture of traditional book layouts, I saw the manmade world around me as exactly that – manmade! I saw the intentional simplicity of all the designs around me, and it was amazing.

Setup of my Rails Survey App

After officially entering the world of rails a couple weeks ago at the Flatiron School, I decided to start a personal rails project to solidify my skills. I chose to put the survey porition of my undergrad these online. The survey asks respondents questions about their perception of a learning experience. The data is ideally displayed in a series of radar graphs and bar graphs. This blog post focuses on how I collect survey responses in the correct format.

Luckily for me, the Flatiron Dean made a Quiz App a public repo during class. I forked this repo, which already had 5 models: Quiz, Question, Choice, Answer, and User. My task now was to calculate the results.

Collect the Rails App Survey Results

For the purpose of this post, the survey has 48 questions, which is broken down into 6 sets of 8 questions. The method I made to solve this problem was three-tiered:

  1. Collect survey answers in sets of 8
  2. Correctly compare a user’s answer with all possible choices
  3. Based on the user’s answer, assign that person a score

See the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Quiz < ActiveRecord::Base
  has_many :questions
  has_many :results

  def results_as_set_of_8(user, range)
    score = 0
     self.questions[range].each_with_index do |q, qi|
       q.choices.each_with_index do |c, ci|
         if c.id == user.answers[range.first + qi].choice_id
           score += ci +5 - (2*ci)
         end
       end
     end
     return score/8.0
  end
end
  1. Sets of 8 uses range

    This method takes range as a parameter, so that I can specify which set of 8 questions. The range also gets used to compare the question with its corresponding answer.

  2. Correctly compare a user’s answers with all possible choices

    I used the each_with_index method on the range of questions to find two pieces of information:

    which question id corresponds with the first answer id (start at range.first) as the .each enumerable changes which question is being handled, correspond that change with the appropriate answer id (by proceeding upwards with qi)

    To do this, I specified which answer with:

    ruby user.answers[range.first + qi]

    Once this synchronization between question and a user’s answer is made, I checked all of a question’s choices to see if their id matches the answer’s choice id, of which it has only one.

  3. Based on the user’s answer, assign that person a score

    Another challenge was associating number values with the choice object, which has the single String attribute of :content. Becuase the survey arranges choice.content from values of 5 to 1, such as, “Strongly Agree, Agree, Neither Agree nor Disagree, Disagree, Strongly Disagree,” I ended up making a simple formula to assign the right score:

    ruby score += ci +5 - (2*ci)

    Everytime the user’s answer’s choice id matches a quesiton’s choice id, then based on its position in a.choices, the above algebraic expression calculates the right score. Furthermore, this method finds the score sum because at the end, it finds the average score with score/8.0.

Coding Takeaways

  1. Make it work

    Things might have been easier for me if I gave choices a value attribute. Tracking the value of a choice would make they survey app more flexible, such as if i wanted to randomize the order in which choices appear.

    But rather than going backwards over my code, I moved forward first, trusting my ability to refactor in the future.

  2. Use debugger

    Initially, I missed how to correctly associate user.answers with quiz.quesitons. My method worked for the first set of 8 questions, but not for sets after that. By looking at the progression of the code through debugger, I visibly saw where my method failed becuase the if c.id statement was never triggered.

By focusing on making it work, and looking at the code with detail and granularity, I quickly made my app functional. Though next time, I’ll add a value attribute to the choice model and make my life easier.