Posts Tagged Rails
My Profile page: a RESTful single resource using Formtastic
I’ve just implemented the My Profile tab for Sano:

Can I write 500 words about? Well, I can try.
I like using RESTful routes. In case you don’t know what they are let me try to explain it quick, at least the relevant part. You normally have a set of route rules that would point /movies to the movie listing, /movies/new to a form to add a new movie, /movies/123 to see the movie 123. With RESTful routes in Rails all that is done automatic in a single line:
map.resources :movies
What you are doing is defining a resource. The resource has several actions that can be performed on them:
- index (a.k.a.: listing)
- new
- edit
- create
- update
- destroy
In Sano I have a weights resource that is a very fine example of it:
map.resources :weights
Running the rake routes command we can see all the routes it generate:
weights GET /weights(.:format) {:action=>"index", :controller=>"weights"}
POST /weights(.:format) {:action=>"create", :controller=>"weights"}
new_weight GET /weights/new(.:format) {:action=>"new", :controller=>"weights"}
edit_weight GET /weights/:id/edit(.:format) {:action=>"edit", :controller=>"weights"}
weight GET /weights/:id(.:format) {:action=>"show", :controller=>"weights"}
PUT /weights/:id(.:format) {:action=>"update", :controller=>"weights"}
DELETE /weights/:id(.:format) {:action=>"destroy", :controller=>"weights"}
You see the (.:format) in there? That means that every route is also accessible in alternative formats. For example: xml. Go and try it, add some weights and access http://sano.pupeno.com/weights.xml.
If you are curious, the code for that is this:
def index @weights = user.weights.all respond_to do |format| format.html format.xml { render :xml => @weights } end end
I now want everything to be a resource. How can “my profile” be a resource? Well, it’s not hard. It’s not a collection resource, it’s a single resource. There’s no list of profiles, no creation of new profiles or destruction of profiles. There’s only editing and updating of a single profile (which is actually your user).
It turns out that in Rails, that’s very easy to define:
map.resource :profile, :only => [:edit, :update]
Notice how it says “resource” instead of “resources” and it only allows certain actions. Rails is really quite flexible here, logging in is also a resource. It’s called session and you can create them, by logging in, or destroy them, by logging out (no editing). There’s also an extra action needed by OpenID. This is the route definition:
map.resource :session, :only => [:new, :create, :destroy], :member => { :finish_creating => :get }
The “member” part specifies that action to be only for items, not for the whole collection. If it was a collection resource, you could have extra listings. The same way you have index, you could have sorted_index.
The form in the my-profile-page is an example of what Formtastic is good at. This is the whole form:
<% semantic_form_for @user, :url => profile_url do |f| %> <% f.inputs do -%> <%= f.input :name %> <%= f.input :email %> <%= f.input :height, :hint => "meters" %> <%= f.input :gender, :as => :radio, :collection => [["Male", false], ["Female", true]] %> <%= f.input :birthday, :start_year => 1900, :end_year => Time.now.year %> <% end -%> <% f.buttons do -%> <%= f.commit_button :label => "Update profile" %> <% end -%> <% end %>
Special thanks to Ryan Bates who covered the gender case in Railscasts episode 184 and Eifion Bedford of ASCIIcasts for making it easy to find. It surely would have take me some time to figure it out.
Can you please update your profile on Sano?
There you go 553 words!
I love to code
I said I was done for the day more than 6 hours ago, but I love to code, I couldn’t stop. I wanted to implement a small feature: make the creation of new weights simpler for the common case and I did it:

Note: That change is not yet deployed. I don’t play with servers while I’m half-asleep.
This took awfully long. The problem was that in the process I’ve found a bug in Formtastic, which made me realize I was running version 0.2.4 when the latest version was 0.9.2. That is because I was using justinfrench-formtastic:
config.gem 'formtastic', :lib => 'justinfrench-formtastic'
when I should have been using formtastic from gemcutter:
config.gem 'formtastic'
When I moved to 0.9.2 I’ve found two bugs on it, one was temporary solved and then reverted (and I fixed it by reverting the revertion) and the other is still there but I’m not 100% confident my solution is the appropriate one. At any rate I forked Formtastic in GitHub, fixed the bugs and made a merge request.
Conclusion: Git is great, GitHub is great, Formtastic is great, open source is great, Rails is great and yes, I am great ;)
Sano is open for business
I really wish I was able to get farther in one day, but I think it’s good enough that I went from idea to deployed app. On retrospective I wasted too much time figuring out formtastic. I don’t regret doing it because it was in my TODO list and in the long run it should make me more productive, but in the short run maybe I should have used the good old forms.
The other two big waste of times was CSS and tables and an issue with the Ruby OpenID gem. Both problems I encountered before and both times I gave up trying to solve them and moved on. I should have moved on again this time; but instead I figured them out.
The application is at http://sano.pupeno.com. Please don’t break it ;) Remember to log in and if you add data I’ll be grateful as it’ll make my migrations more realistic:

I’m done for today.
Super Exception Notifier
I like knowing when something goes wrong with my web apps, so I’m using Super Exception Notifier to get by email a report should any exception be raised in the app. If you go to Super Exception Notifier’s site you’ll see some instructions on how to add it to your project. This is how I do it.
Add the gem requirement in environment.rb:
config.gem 'super_exception_notifier', :version => '~> 2.0.0', :lib => 'exception_notifier'
Then be sure to have gemcutter in your gem sources:
*** CURRENT SOURCES ***
http://gemcutter.org
http://gems.rubyforge.org/
http://gems.github.com
If you don’t have it, you can add it this way:
To install the gem, in your Rails project run:
Create a file in config/initializers, I’ve called it exception_notifier.rb and inside I’ve set up the only really needed value for the notifications, the email address:
# Notification configuration ExceptionNotifier.configure_exception_notifier do |config| config[:exception_recipients] = %w(pupeno@pupeno.com) end
The last task is to make your application controller noisy by adding one line to it (the second one of course):
class ApplicationController < ActionController::Base include ExceptionNotifiable #... end
You also need to be sure that you have ActionMailer properly configured, otherwise no mail is going to get through.
Merging users
Remember that I said that when you log in, your ghost user has to be merged with the real user? Well, this is the code for doing it:
class User < ActiveRecord::Base #... def merge(user_id) if user_id != nil user = User.find(user_id) user.weights.each do |weight| weight.user = self weight.save end user.destroy end end end
The problem with this is that it’s very error prone. You have to make sure that every model that is related to the user model gets properly handled.
Simplifying the weight CRUD
After a rather long fight with formtastic I have a better CRUD for weight:

But now that I think about it, there shouldn’t be a measured at in this view. That should be in an advanced new-form.
Creating the weight model and scaffolding
With one command line I’ve created the weight model and the scaffolding, a fully functional CRUD little app without my Rails app. I know all Rails developer are rolling eyes now; but I still think this is awesome. It gets you up and running so fast:
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/weights
create app/views/layouts/
create test/functional/
exists test/unit/
create test/unit/helpers/
create public/stylesheets/
create app/views/weights/index.html.erb
create app/views/weights/show.html.erb
create app/views/weights/new.html.erb
create app/views/weights/edit.html.erb
create app/views/layouts/weights.html.erb
create public/stylesheets/scaffold.css
create app/controllers/weights_controller.rb
create test/functional/weights_controller_test.rb
create app/helpers/weights_helper.rb
create test/unit/helpers/weights_helper_test.rb
route map.resources :weights
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/weight.rb
create test/unit/weight_test.rb
create test/fixtures/weights.yml
exists db/migrate
create db/migrate/20091121135320_create_weights.rb
And this is what I’ve got:






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:
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:

rails sano
For those that never used Ruby on Rails, basically you run:
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
I went and run the testing server and here I am:

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
Posted by Pablo in announcement on 2009-11-21
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 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?)
- 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!!!

Recent Comments