Pablo's blog

A bit of this, a bit of that and a lot about computers

Archive for the tag “Rails”

Profile models

The profiles in Sano are built out of two models:

  • User
  • OpenId

The reason to have an OpenId model and not just one field in the User model is that I like giving users the possibility of defining more than one OpenId provider. StackOverflow does that and since I use my own OpenId server, the day it was down, I was really grateful I could still use my myOpenId account to log in.

So I created the two models:

./script/generate model user name:string email:string height:float gender:boolean birthday:date
./script/generate model open_id user_id:integer identifier:string display_identifier:string

and then I used Matthew Higgins’s foreigner to define the foreign keys. The end result follows.

Migration for users:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name
      t.string :email
      t.float :height
      t.boolean :gender
      t.date :birthday
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

Migration for OpenIds:

class CreateOpenIds < ActiveRecord::Migration
  def self.up
    create_table :open_ids do |t|
      t.integer :user_id, :null => false
      t.string :identifier, :null => false
      t.string :display_identifier
      t.timestamps
      t.foreign_key :users
    end

    add_index :open_ids, :identifier, :unique => true
  end

  def self.down
    drop_table :open_ids
  end
end

Both models:

class User < ActiveRecord::Base
  has_many :open_ids
end

class OpenId < ActiveRecord::Base
  belongs_to :user
end

A thousand more words:

sano-002

rails sano

For those that never used Ruby on Rails, basically you run:

rails <projectname>

and you have a complete runnable Rails project with lot’s of placeholders so that you don’t have to worry about where to put stuff and making sure things work well together. Just after doing

rails sano

I went and run the testing server and here I am:

sano-001

That’s my development browser. Normally I use Safari or Chrome, but for development I use Firefox equipped with two important plug ins. The most important one is Firebug. The other one is Web Developer. If you are into web programming at all, you should check them out.

I'm going to do an experiment today

I’ve started learning C# and ASP.NET MVC about 5 or 6 months ago. While learning I’ve developed a clone of Reddit that had a very clear differentiator: you could see the messages and the web page at the same time. When I was close to completion Reddit released exactly that feature. I scrapped that project.

Then I had the idea of making Is it Science Fiction?. I started coding and since the day of the idea to the day of deployment I had one full day of work and four days of part time work. I was really surprised by my productivity, and quite satisfied.

When I started to write some complex features for Is it Science Fiction? I hit a roadblock on writing tests for it. What sometimes is called functional tests are not trivial in ASP.NET MVC. I mean tests that hit controllers properly initialized and the database with some fixtures (but not touching HTTP). I spent three days developing a framework for those kind of tests when I realized I was wasting my time, Rails could do this out of the box.

I’ve decided to re-write Is it Science Fiction? on Ruby on Rails while I was reading Agile Web Development with Rails. Unfortunately, it took me more than a month to do it. I’ve moved to Rails because I thought it was more mature and had many more libraries and utilities that would make me more productive. I was extremely disappointed. But, my first ASP.NET MVC project also took a long time, while I was reading the book; so it’s not fair to compare my time at re-writing Is it Science Fiction? because I was reading a book while doing it and not skipping any part of the book even when it had no application to my current project.

I want to find out how productive I’m in Rails. So I’ve decided to try to do a simple project in a weekend. That day is, starting today. Today I will run the rails command and create the project and if everything goes well, today or tomorrow you’ll be able to use the app. It’s not going to be a very complex app; after all it’s only one weekend and I do aim to having tests and clean code. I’ll try to post as I go along so my blog is going to be quite noisy.

The project code name is Sano, it means health in Esperanto. It’s a health tracker. Both my wife and me want to be more healthy and the first step of course is for me to code an app for it. Let’s start with a spec for Sano.

Sano

Sano is a health tracker that can track many different health parameters of a person. The goal is for that person to have a clear view of how healthy they are and their health trends (am I getting better or worse?). It should also be a good tool to convey clear scientific non-biased information to a medic when the users needs that.

Countries that doesnt use SI

Countries that doesn't use SI

All units of measurement will be SI. My apologies to those three countries in the world that have not adopted these units and are using weird obsolete old units. Grow up!

Authentication

A user should be able to use the site without doing absolutely any authentication. The user should be able to enter data, see tables, see charts and all that information is stored in reference to a “ghost user”, that is session only. If the user closes the browser all that data will become inaccessible. The user will be warned several times about the potential losing of data if they are trying the application in this fashion. The warnings would be as notices on the page itself and if possible a pop up when closing the page.

For logging in, Sano will use OpenID and only OpenID with the usual friendly login pages. No other information will be asked and no registration page will exist. Users already in the system will log in to see their previous records, the rest will register on the fly silently. If a user has session data before logging in (previous paragraph), that data is going to be merged with their authenticated user.

The site won’t have any publicly viewable section. Even the sections that you can see without logging in are shown differently user by user. In a sense it’s like Facebook.

Profile

The profile of a user will be a set of meta-data associated with that user. It will contain the following fields:

  • name: the real name of a person (not broken into last name and first name, because that doesn’t make any sense; how would Madonna use my system?)
  • email
  • height (consideration: what about varying height? like in children, for version 2 or 3 or 23)
  • gender
  • birth date (important to know the age, maybe).

all fields are going to be optional.

Trackers

Sano will start with two trackers:

  • weight
  • blood pressure (systolic, diastolic and pulse)

Each of the trackers will have its own CRUD to add data and will be implemented as standalone controllers (that meaning no meta-tracker that can track anything astronaut-architect-style).

Each of the data points will be stored with time and date (most weight trackers only track date; this will allow for time variation compensation) and the form should allow the user to enter a data point as happened now (or just now) but also with a specific date and time (don’t ask for any more precision than the hour of the day, but store up to the seconds, just in case).

Every tracker should have a table for updating, deleting and exporting (it should export to CSV) but also a graphic view that is tracker dependant.

Weight tracker

The weight tracker asks only for one number: the weight. The first iteration will work only with kilograms.

The weight tracker will ask you to complete your profile to include your height to be able to calculate the range of acceptable weight.

In the table view three colors will be used, red, yellow and green to show under or over weights according to your height, gender and maybe age.

The chart should be a simple line chart at the beginning. In a second version it should have a weighted average according to the Hacker’s Diet rules.

Blood pressure tracker

Three pieces of information will be asked in this tracker:

  • systolic
  • diastolic
  • pulse

The table view again will use the red, green and yellow colors to show dangerous values.

The chart should be a bar chart showing sets of three bars (one for each measurement). Each of the three vars will be in a different tone of green to be able to distinguish them and when they reach dangerous levels they will turn yellow and red with different tones accordingly.

Dashboard

The dashboard is a chart of all or most of the data you have in the system. A one place to look at your current health.

Third party access

All the data in the system is private and sensitive so it’ll be kept private. But, a very important aspect of the system is to give other selected people access to your data.  There will be two ways to grant a third party person access to the system: permanent or temporary (both are revokable at any time).

The permanent access would mean giving access to another registered user in the system. That’s most likely your main medic or a medic that’s treating you. Consideration: what about write access to a trusted third party that helps keep track, what about allowing your medic to add information or annotations that require your approval?

It would be nice to be able to keep that kind of close relationship with a medic, but it’s not very realistic. So there’s a temporary access system. You will log in to your account and generate a token for half an hour access to your profile. The person that gets the token will be able to see your profile for half an hour. The use case is that you go to the doctor, you pick your phone (potentially while you are at the weighting room), log in to Sano, generate the token and the URL would be displayed big on the screen. You can then show your phone to your medic and he/she would have half an hour access to your data.

Let’s code!

It’s not a huge app, but it’s not a hello-world either. I don’t plan to be able to do all of it on one weekend and there are some parts, like charts, which I desgined without knowing the capabilities of available charting libraries. It may not be possible to do some of the things I mentioned without writing some custom charting which is out of the question.

Since my goal is to have something deployed, as soon as it is barely usable I will deploy it, and then I’ll keep adding features until the end of the weekend (or whenever I have to stop).

Sano is the code name for the app, I’m not sure about the public name. If you have any suggestion with an available domain name, please let me know (note: I won’t buy domain names unless you are doing it out of good faith and selling it for no more than 200% of its cost).

That’s all, let’s code!!!

Quick and dirty tabs on Ruby on Rails

For my Ruby on Rails pet project Is it Science Fiction? I’ve reached that point when I wanted to show tabs. You know, for the menu, on top of the page. I quickly wrote something like:

<ul class="tabs">
  <li><%= link_to 'Home', root_url %></li>
  <li><%= link_to 'Recommend', new_item_url %></li>
  <li><%= link_to 'Ranking', items_url %></li>
  <% if session[:user_name] -%>
    <li><%= link_to 'Log out', session_url, :method => :delete %></li>
    <li><%= link_to 'My Profile', edit_profile_url %></li>
  <% else %>
    <li><%= link_to 'Log in', new_session_url %></li>
  <% end %>
</ul>

and styled it like the Listamatic Unraveled CSS tabs. And everything was good, except that the current tab wasn’t highlighted. Highlighting it is a matter of setting the correct class for it.

For that I created a new version of link_to that adds the “current” class to a link if it points to the current page. That is not very hard actually, but you have to consider that some tabs, like Ranking, are not only highlighted when that page is show, but when any subpage (like a ranked item) is shown as well. After trying many solutions (in an effort to find the simplest one) I’ve settled for link_to2 and the tabs now look like this:

<ul class="tabs">
  <li><%= link_to2 'Home', root_url %></li>
  <li><%= link_to2 'Recommend', new_item_url %></li>
  <li><%= link_to2 'Ranking', items_url, {:extra_current => {:controller => :items, :action => :show}} %></li>
  <% if session[:user_name] -%>
    <li><%= link_to 'Log out', session_url, :method => :delete %></li>
    <li><%= link_to2 'My Profile', edit_profile_url %></li>
  <% else %>
    <li><%= link_to2 'Log in', new_session_url %></li>
  <% end %>
</ul>

Look at the Ranking tab, it has an extra_current that adds other pages to be treated as current. The code to do this is the following (I’ve put it in application_helper.rb):

module ApplicationHelper
  def link_to2(*args, &block)
    if block_given?
      options      = args.first || {}
      html_options = args.second || {}
    else
      name         = args.first
      options      = args.second || {}
      html_options = args.third || {}
    end

    if current_page?(options) or as_array(html_options[:extra_current]).any? {|o| current_page2? o}
      html_options[:class] = add_class(html_options[:class], "current")
    end

    html_options.delete(:extra_current)

    if block_given?
      link_to(options, html_options, &block)
    else
      link_to(name, options, html_options, &block)
    end
  end

  private

  def add_class(classes, new_class)
    ((classes or "").split(" ") << new_class).join(" ")
  end

  def as_array(o)
    if o == nil
      []
    elsif not o.is_a? Array
      [o]
    else
      o
    end
  end

  # current_page? of {:controller => :blah, :action => :bleh} when the routes also require an id raises a route error. current_page2? doesn't.
  def current_page2?(p)
    current_page? p
  rescue
    return false
  end
end

Feel free to pick the code and use it in any way you want. I’m thinking of turning it into a gem, but I need a better name than link_to2, any ideas?

Ensuring the displaying of flash messages in Ruby on Rails

Ruby on Rails has a special object called flash which hold its contents for one more request. It’s particularly useful to show messages after a redirect. Since it’s good style to redirect after each succesful form post, that’s where you put the messages such as: “You’ve logged in”, “Thank you for your feedback”, “The book has been added”, etc.

This flash object looks like a hash table. I normally use two items in there: notice, for good stuff and errors, for bad stuff. I want these messages to be displayed in all pages, so whenever something bad or good happens, I just drop stuff in the notice or error and forget about it. This is trivial to do, I just put this:

<% if flash[:error] -%>
  <p class='error'><%=h flash[:error] %></p>
<% end -%>
<% if flash[:notice] -%>
  <p class='notice'><%=h flash[:notice] %></p>
<% end -%>

on the application layout.

The problem with doing that is that it doesn’t look nice. I expect error messages and success messages to be near the forms or UI elements I’m interacting with. That means that every view or page will put it in a different location. No problem, you just add that same snippet where you want the messages to appear.

Then there’s a second problem: you get messages twice. If you remove them from the application layout, then you have to remember to put in absolutely every view, even those that you don’t expect to never show an error or notice. I don’t trust myself to always remember to do anything, so what happens is that I can’t just drop something in the flash and expected it to be show, I have to check every time.

I’m doing this in for a pet projects with less than 10 views, but I think big. I think of the project having 100 views and three coders than don’t know all the implicit rules, like adding the display message snippet to every view they create.

I’ve came up with this solution. I created a partial view with this content:

<% if not @messages_rendered -%>
  <% if flash[:error] -%>
    <p class='error'><%=h flash[:error] %></p>
  <% end -%>
  <% if flash[:notice] -%>
    <p class='notice'><%=h flash[:notice] %></p>
  <% end -%>
<% end -%>
<% @messages_rendered = true -%>

That partial view is rendered from the views and also from the application layout, but it displays the messages only once. Thankfully Rails renders the partials inside the views first, so that the messages gets displayed according to the view, and if the view didn’t display them, the application layout will.

NetBeans could make the Ruby on Rails experience great

NetBeans could make the Ruby on Rails experience great for the vast majority of developers who are using Windows, where installing Ruby, Rails, PHP, MySQL, Python, etc is always a pain and the end result is ugly. But it falls short in some important ways which turned my experience with it into a nightmare.

The reason I say “for developers using Windows” is because I believe that for everybody else, the experience is great already. Or as good as it can be and NetBeans can be an excellent IDE, but not improve the installation and managing experience.

This is my story, my rant.

I downloaded the latest NetBeans and installed it. When creating my first Ruby project, I encountered the first problem. Ruby chocked on my username, which was “J. Pablo Fernández”. You could say it was my fault. Windows 7 asked for my name and I typed it. I wasn’t aware it was asking for my username. Even then I would have typed the same, because Windows 7 doesn’t distinguish between usernames and names, and in the 21st century, computers should be able to deal with any character anywhere.

I know it’s not NetBeans’ fault, it’s Ruby’s. But! Can you imagine a Software Engineer telling Steve Jobs “oh, copying files in a Mac behaves weirdly because it uses rsync and that’s its behavior, you see, it makes sense because…”? Of course Steve would have interrupted: “You’ve failed me for the last time”. The next developer would have patched rsync, trying to get the patch upstream, or creating an alternate rsync or stop using rsync.

I’ve spent many hours creating another user, migrating to it, which in Windows is like 100 times harder than it should.

Hours later, as soon as I created a project I got a message saying that I should upgrade gem, Ruby’s package manager, because the current version was incompatible with the current Rails version. By then I had already played with NetBeans’ gem interface telling it to upgrade everything, it should have upgraded gem as well, not just the gems. Every single developer out there running NetBeans must be encountering this error, and indeed there are quite a few threads about it on forums.

Trying to upgrade gem with NetBeans was impossible. I think what they did to install and upgrade gems in NetBeans is excellent, but failing to upgrade gem itself was a huge drawback. This one was NetBeans’ fault. Neverfear, let’s do it from the command line.

When doing it from the command line I encountered another error:

\NetBeans was unexpected at this time.

Looking around it seems it’s because of the spaces in “Program Files (x86)”. That means that the command line environment for Ruby that NetBeans installs is broken for everybody. I repeat: everybody. The answer: install it somewhere else.

Well, I have two things to say about it: first, fix the freaking thing, Ruby, gem, whatever. Paths can have spaces and all kind of weirdness. It’s a big world full of people speaking languages that can’t be represented with ASCII and people that believe computers should do our bidding, instead of the other way around. “If I want spaces you better give me spaces, useless lump of metal and silicon”.

Second, if you know one of your dependencies is broken, try to avoid triggering the broken behavior or at least warn the user about it. “We see you picked C:\Program Files (x86)\ to install NetBeans, which is pretty standard, but you know, Ruby is broken and can’t work in there, not even JRuby, so if you plan to use those at all, please consider installing it somewhere else.”

I uninstalled NetBeans, or tried to. The uninstaller didn’t work. I deleted it and tried to install it on C:\ProgramFilesx86, which failed because some other directory created by NetBeans somewhere else existed from the previous installation, which halted the installation. I started a dance of run installer, remove dir, run installer, remove dir, run installer… until it worked.

Once I finished I found out that NetBeans installed in C:\ProgramFilesx86\Netbeans 6.7.1. Yes, that’s a space. Oh my…

As a bonus, NetBeans can’t automatically find Sun’s JDK in its default directory. I had to point to it by hand. Sun was, as usually, absolutely disrespectful of the platform conventions and installed its crap in C:\Sun. I would have picked another place but I thought “I’m sure some stupid program will want to pick that shit from there”. Silly me.

12 hours have passed and I still haven’t been able to write a single line of source code. I contemplated installing Ruby by hand, but it’s so ugly that I decided I’m not going to use Windows for this. I’m going to work on another platform where installing Ruby is trivial and where I would probably never touch NetBeans because I have other editors.

I know there’s a lot not really related to NetBeans here, for example, the fact that working with Python, or Ruby or MySQL in Windows is a pain; but it’s a great opportunity for NetBeans. There are developers wanting to use those languages and environments and if NetBeans makes it easy for them, they will pick NetBeans not because of its editor, but because of everything else (which is what I was hoping to get out of NetBeans).

Aside from doing some usability tests, the people working on NetBeans should learn from the people working on Ubuntu (not the people working on Evolution) and instead of asking me for debugging traces when I report a simple obvious bug and then tell me it’s not their fault, they should submit those bugs upstream, to Ruby, gem, or whatever. Whenever someone like me submits that bug to NetBeans they should mark it as duplicate of an existing open bug that points to the upstream bug. I would have followed that link and told the Ruby developers “wake up!”. As it is, I didn’t. It’s too much work for me.

Reviewed by Daniel Magliola. Thank you!

Playing with Ruby

This is a remake of Installing Rails 2 on Ubuntu but targeting Ruby in general and with some improvements. Essentially the same, actually, but more usable, at least for myself.

Ubuntu, like many other free operating systems, have a beautiful package management system that will track what depends on what, what is installed, what is not, what is not longer needed, which versions of each. If you tamper with it, you are asking for trouble. If you do a manual upgrade, from sources, eventually a package upgrade will downgrade your version or some other application being incompatible will not work. And once you start throwing files in /usr, you start to ask for trouble. I’ve been using this type of operating systems for years and I’ve learned this by experience.

Read more…

Installing Rails 2 on Ubuntu

Ubuntu, like many other free operating systems, have a beautiful package management system that will track what depends on what, what is installed, what is not, what is not longer needed, which versions of each. If you tamper with it, you are asking for trouble. If you do a manual upgrade, from sources, eventually a package upgrade will downgrade your version or some other application being incompatible will not work. And once you start throwing files in /usr, you start to ask for trouble. I’ve been using this type of operating systems for years and I’ve learned this by experience.

Nevertheless you, as I, want to try and code with Rails 2, right? Well, this is how I installed it in my Kubuntu box (should work the same for any Ubuntu and Debian derivate as well as others). I’ve decided to install everything on /opt/rails. I like to keep more-or-less self-contained directories in /opt. So I started with:

Read more…

Post Navigation

Follow

Get every new post delivered to your Inbox.

Join 377 other followers

%d bloggers like this: