Lee's RailsConfPlan at MyConfPlan
Following Daniel’s lead, here are the talks that I’m thinking of attending. So far I only looked at the titles of the talks, I’m sure I’ll do some switching once I look at them more in depth. Anyway, if you decide to look Daniel up while you’re there, you might want to look me up too, so I can translate his Swiss accent for you.
Chris, Sol and Nick… tag… your turn.
RailsConf 2007 - Here we come!
I just completed a first pass at setting my schedule for RailsConf.
Check it out at MyConfPlan. In any case go check out MyConfPlan which is a pretty cool Rails application.
As usual I am looking forward meeting many of the people I have met last year. Also if you are from Switzerland and doing Rails work, try to hunt me down, I would love to talk to you. It’s also fun that we are going to meet Kirk again, and “old” mate from Denver that is now leaving in Portland.
Forgot Password?
I did it again…forgot my password. Now if everyone could offer an openid login like Highrise. This time it happened on myconfplan, while I was organizing my schedule for next weeks RailsConf. As I didn’t find a link to reset the password on myconfplan, I send an email to their support. Dr Nic replied promptly and said he didn’t implement this yet on this wedsite, but he could manually reset the password. Well, recently I implemented that feature for MySpyder.net (one of our forthcoming web applications). So I send him some code snippets. Not sure if Dr Nic will use them, but maybe some of our blog readers may be interested, so here we go.
They are several ways to implement a "Forgot Password? This time we choose to send out a “reset password” link that is valid for 24 hours. This link lets the user login, bypassing the standard login, and showing the change password screen.
First lets add a migration.
Migrationclass ForgotPassword < ActiveRecord::Migration def self.up add_column :users, :reset_password_code, :string add_column :users, :reset_password_code_until, :datetime endclass ForgotPassword < ActiveRecord::Migration
def self.down remove_column :users, :reset_password_code remove_column :users, :reset_password_code_until end
def self.up
add_column :users, :reset_password_code, :string
add_column :users, :reset_password_code_until, :datetime
endend
“Forgot password” form.
Then add a “forgot password” form, allowing the user to submit the email to which the “reset password” link will be emailed. When the form is submitted, the controller creates a ‘reset password code’ that is valid for one day, and sends an email to the user.
UserController#forgot_passworddef forgot_password user = User.find_by_email(params[:email]) if (user) user.reset_password_code_until = 1.day.from_now user.reset_password_code = Digest::SHA1.hexdigest( "#{user.email}#{Time.now.to_s.split(//).sort_by {rand}.join}" ) user.save! UserNotifier.deliver_forgot_password(user) render :xml => "<errors><info>Reset Password link emailed to #{user.email}.</info></errors>" else render :xml => "<errors><error>User not found: #{params[:email]}</error></errors>" end end
Send email with the ‘reset password’ link.
When the user receives the “reset password” email and clicks the link to reset the password, the reset_password method is invoked on the controller. The user associated with the “reset_code” is found, and if the the reset_code is not yet expired the user is automatically logged-in and redirected to the account page where he can change his password. Note that by adding an expiration attribute for the code, we don’t need to run a cleanup batch process to invalidate these codes. Not in the following code we redirect to a “.swf” file. This was an early experiment where the user interface of the application was written in Flex. We are currently rewriting it to use a more traditional html and css approach.
UserController#reset_passworddef reset_password user = User.find_by_reset_password_code(params[:reset_code]) self.current_user = user if user && user.reset_password_code_until && Time.now < user.reset_password_code_until redirect_to logged_in? ? "/MySpyder.swf?a=account" : "/MySpyder.swf?a=login" end
The email is simply send using the following ActionMailer.
UserNotifierclass UserNotifier < ActionMailer::Base def forgot_password(user) setup_email(user) @subject += 'MySpyder.net - Reset Password' @body[:url] = "http://myspyder.net/reset_password/#{user.reset_password_code}" endclass UserNotifier < ActionMailer::Base
protected def setup_email(user) @recipients = "#{user.email}"
def forgot_password(user)
setup_email(user)
subject</span> += <span class="s"><span class="dl">'</span><span class="k">MySpyder.net - Reset Password</span><span class="dl">'</span></span> <span class="iv">body[:url] = "http://myspyder.net/reset_password/#{user.reset_password_code}"
endfrom</span> = <span class="s"><span class="dl">"</span><span class="k">adminmyspyder.net" @subject = "[myspyder.net] " @sent_on = Time.now @body[:user] = user endend
And the view for the UserNotifier is the following
forgot_password.erb<%=<%= @user.email %>,
You can reset your password by using the following link <%= @url %>
Thank your for using MySpyder.net
TextMate filetype detection for script/runner Rails scripts
So you’re building some righteous automation for your killer web 2.0 app, placing scripts in RAILS_ROOT/script that you can call from cron for nightly maintenance, etc. To bootstrap your rails environment, you decide to use the shebang feature of script/runner, available since changeset 5189. When you start to edit the script in TextMate (you are using TextMate, aren’t you?) there is no syntax highlighting to be found! It’s all plain text with no colors, and none of your ever-so-helpful keyboard macros work! Frightful. Well, take a deep breath, because together, we’re going to get the filetype detection magic working for you.
Before we get started, it’s helpful to know how filetype detection works. TextMate does a couple of different types of filetype detection — the first is based off of the extension, so if you named your script with a .rb extension, you are probably wondering what in the world I’m rambling about. Dude. It just works.
However, if you followed the rails convention for scripts, and did not use an extension with your filename, keep reading. The second type of detection works by scanning the so called “shebang” line at the top of the script which tells the shell (and in this case TextMate) which interpreter to use to evaluate your script — this is how we will tell TextMate that script/runner really means ruby.
First of all, you’ll need to fire up the Bundle Editor and select “Languages” from the drop-down filter. Expand the “Rails” node, and then select the “Ruby on Rails” language. On the right side, you should see the definition being used by TextMate to detect the Ruby on Rails scope. If you have not modified your bundle, you’ll probably see that it is using a fileTypes to look for .rxml files. This is where we want to insert the following line:
@ firstLineMatch = ‘^#!.*(script/runner)’;@
Here’s a screenshot of what it should look like when you are done:

Now go back to your script and enjoy all the colorized, scope-aware editing goodness that is TextMate!
Mapping Rails Errors to Flex Fields.

We extended the com.wheelerstreet.utils.ValidatorForm to add support for Rails Errors. Saving a form is a two step process. First, client side validation, the Signup button only gets enabled if the form is valid from a client side point of view. Step 2, server side validation, the user press the signup button and invokes the Rails UserController#create method
class UsersController < ApplicationController
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
self.current_user = @user
format.xml { head :created }
else
format.xml { render :xml => @user.errors.to_xml(:dasherize => false) } end
end
end
endIf saving the user fails then Rails return the xml version of the errors:
@user.errors.to_xml(:dasherize => false)
Now we need a generic way to deal with these errors. We created the Flex RailsErrors class to manage the returned xml. And we created the RailsValidationForm that extends the com.wheelerstreet.utils.ValidatorForm. The RailsValidationForm class can be bound to a RailsErrors instance. So the result handler of the Flex Cairngorm Flex SignupCommand we just set the errors on the model locatorL
var errors:RailsErrors = new RailsErrors(data.result as XML); MySpyderModelLocator.getInstance().signupErrors = errors;
The signup.mxml page contains the following signup form
<mx:Canvas
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:rails="org.onrails.rails.*"
>
<mx:Panel x="162" y="64" title="Signup - Your Account Details.">
<!-- Instance of org.onrails.rails.RailsValidationForm -->
<rails:RailsValidationForm
id="submitForm"
defaultButton="{signupButton}"
validators="{validators}"
fieldMap="{{Email:email, Password:password}}"
railsErrors="{MySpyderModelLocator.getInstance().signupErrors}"
x="98" y="89">
<mx:FormItem label="email">
<mx:TextInput id="email" />
</mx:FormItem>
<mx:FormItem label="Password">
<mx:TextInput id="password" displayAsPassword="true" />
</mx:FormItem>
<mx:FormItem label="Confirmation">
<mx:TextInput id="passwordConfirmation" displayAsPassword="true" />
</mx:FormItem>
<mx:Button id="signupButton" label="Signup >>" click="signup()" enabled="{MySpyderModelLocator.getInstance().signupButtonEnabled}"/>
</rails:RailsValidationForm>
</mx:Panel>
<rails:RailsErrorBox x="487" y="64" width="301" height="178"
errorMessage="errors prohibited this new account to be created"
errors="{MySpyderModelLocator.getInstance().signupErrors}"
visible="{MySpyderModelLocator.getInstance().signupErrors && MySpyderModelLocator.getInstance().signupErrors.hasErrors()}"
/>
</mx:Canvas>The RailsErrorBox just displays the text of all error messages and is only visible if there are any Rails errors.
Now all the magic happens in the org.onrails.rails.RailsValidationForm railsErrors setter.
public function set railsErrors(errors:RailsErrors):void {
_railsErrors = errors;
if (_railsErrors==null || !_railsErrors.hasErrors()) {
resetErrors();
} else {
for each (var field:String in _railsErrors.fields) {
if (_fieldMap[field])
_fieldMap[field].errorString = field + ' ' + _railsErrors.getFieldErrors(field).join(', ');
}
}
}The key is to associate the Rails error message with the field is simply to set the errorString on the field.
I just created this code this morning at breakfast so it’s really a work in progress. For instance it doesn’t support Rails attributes that are more than one word. But this goes hand in hand with the ActiveResourceClient and can be useful I hope to others trying to integrate Rails and Flex. So we will create a Google project and post the RailsErrors and RailsValidationForm.
Cairngorm Generators
I looked into Cairngorm a while ago (version 0.95 I believe, pre-ModelLocator area) and didn’t like the fact that you couldn’t use Flex bindings at that time. I recently gave it a second look I liked what I saw. Using Cairngorm is at first very verbose but it provides you with a clear way of organizing your code, which is very beneficial on larger projects. Cairngorm is well documented and there are several nice examples available. Also checkout http://www.cairngormdocs.org/. So yesterday introduced Cairgorm on two Flex projects I am working on.
The first project is a larger Flex 1.5 project (65 actionscript classes, 75 Data transfer object, >100 Mxml views) that I need to migrate to Flex 2.0. I though “great time to start with Cairngorm”. So the first step was to look at all the user gestures for all the screens and create a list of events, map these events to commands, create 3 delegates and services to handle all the remote calls. On paper that was pretty fast to do, but I didn’t want to create all the Cairngorm supporting class by hand. Handily I found the following generator that is a PHP application:
It targets currently only Cairngorm 2.0 and not the newer Cairngorm 2.1. So after generate the supporting classes I had to manually do some changes. But thanks for this tool.
The second project is a smaller Flex application backed by a Ruby on Rails server. And I found the following Ruby on Rails Cairngorm generators at http://code.google.com/p/cairngorm-rails-generator/
Simply copy the generators to your “/vendor/generators” folder, the generators folder will then contain the following generators:
cairngorm command delegate event vo worbservice
Note there are several places in Rails you can set generators, but that did the trick for me. The I created a “src” folder in my Rails root folder and issues the following commands:
Then you can use these different generator commands to build the structure you require, the events, commands, delegates and more.
./script/generate cairngorm org/onrails/myspyder ./script/generate delegate org/onrails/myspyder server ./script/generate command org/onrails/myspyder show_page_watch server ./script/generate event org/onrails/myspyder show_page_watch
I issued the generate script for each of the commands that application needs to support. The main controller now looks as follows (still very early in the development phase)
package org.onrails.myspyder.control
{
import com.adobe.cairngorm.control.FrontController;
import com.adobe.cairngorm.control.CairngormEventDispatcher;
import org.onrails.myspyder.control.*;
import org.onrails.myspyder.command.*;
public class MySpyderController extends FrontController
{
public function MySpyderController()
{
initialiseCommands();
}
public function initialiseCommands() : void
{
// Application Tabs
addCommand( ShowAccountEvent.EVENT_SHOW_ACCOUNT, ShowAccountCommand );
addCommand( ShowPagesEvent.EVENT_SHOW_PAGES, ShowPagesCommand );
addCommand( ShowSettingsEvent.EVENT_SHOW_SETTINGS, ShowSettingsCommand );
// Page List
addCommand( ReloadPagesEvent.EVENT_RELOAD_PAGES, ReloadPagesCommand );
addCommand( AddPageEvent.EVENT_ADD_PAGE, AddPageCommand );
addCommand( ReloadPageEvent.EVENT_RELOAD_PAGE, ReloadPageCommand );
addCommand( RemovePageEvent.EVENT_REMOVE_PAGE, RemovePageCommand );
addCommand( SavePageEvent.EVENT_SAVE_PAGE, SavePageCommand );
// Page Details
addCommand( ShowPageWatchEvent.EVENT_SHOW_PAGE_WATCH, ShowPageWatchCommand );
addCommand( ShowPageWatchResultEvent.EVENT_SHOW_PAGE_WATCH_RESULT, ShowPageWatchResultCommand );
// Html Section
addCommand( ShowOriginalPageEvent.EVENT_SHOW_ORIGINAL_PAGE, ShowOriginalPageCommand );
addCommand( ShowPageSectionEvent.EVENT_SHOW_PAGE_SECTION, ShowPageSectionCommand );
addCommand( SelectPageSectionEvent.EVENT_SELECT_PAGE_SECTION, SelectPageSectionCommand );
}
}
}Let me know your experience with Flex and Cairngorm.
RESTFul Rails from Flex.
As part of the “MySpyder” project I am currently working on we want a Flex front-end to access a RESTFul Ruby on Rails service. You can read more on RESTFul and ActiveResource on David’s blog, on the “release notes” of Rails 1.2, PeepCode as an excellent screencast (not free) on the subject, and many other places.
In short using the RESTFul approach allows to expose and manipulate a Rails model via a predefined set of standard Http requests. For example we have an ActiveRecord named Watch which can be manipulated via the following requests:
| command | url |
|---|---|
| index | # GET /watches.xml |
| show | # GET /watches/1.xml |
| new | # GET /watches/new |
| create | # POST /watches.xml |
| update | # PUT /watches/1.xml |
| delete | # DELETE /watches/1.xml |
This allows for standard CRUD operations. Note rest supports also custom operations and CRUD operations on nested resources (such as a has_many relationship). We won’t address them in the article, but I will certainly need them later in the project.
The Rails application can determined what format to return based on the content type or the extension of the url. We are only interested in xml for the moment.
Some of the advantages of a RESTFul Rails application are that it provides a standard way to organize your controllers, as you will see just in a moment because the controllers are standard most of the code can easily be generated, and because the URL to access the application are standard we can now provide some standard utility class to access a RESTFul server. Rails provides an ActiveResource client class, and I haven’t found one yet for Flex. So I started to write one which I will show here after. Now please contact me or add some comments to this blog if you find anything similar or if you want to help me out writing this class. Another cool feature of writing RESTFul Rails controllers is that you get an API for your application nearly for free. This is the main reason we went down that direction.
Assuming we have an ActiveRecord named Watch we can now generate a RESTFul Ruby on Rails controller issuing the following command
./script/generate scaffold_resource watch
Our server now supports RESTFul http requests.
Now wouldn’t it be nice if we could access the server data from Flex in the following manner:
import mx.rpc.AsyncToken;
import org.onrails.ActiveResourceClient;var watches:ActiveResourceClient = new ActiveResourceClient();
watches.defineResource("http://localhost:3000", "watches", resultHandler, faultHandler);// Note that all the calls are performed in parallel and asynchronously.
watches.list()
watches.show(8)// create
var data:XML = <watch>
<url>www.picnik.com</url>
<xpath></xpath>
<frequency>10080</frequency>
</watch>
watches.create(data)// update
data = <watch>
<id>8</id>
<frequency>10080</frequency>
</watch>
data.frequency = 1440;
watches.update(data)// delete
watches.deleteItem(8)
Now we can. I started to write the ActiveResourceClient actionscript class to allow this. It’s attached at the end of the article. Now, this is a first try I’ve created this morning. So please be critical and let’s improve it together, or even better if you have one or know one that’s way better please point me where I can get it.
To use the ActiveResourceClient just put the ActiveResourceClient.mxml file into the org.onrails folder in your Flex project. Note that you can provide a default result handler and fault handler or set one handler for each specific call, i.e. the watches.create returns an AsyncToken where a dedicated handler can be specified just to handle the result of the creation.
Download: ActiveResourceClient.mxml (renamed file to ActiveResourceClient.mxml)
Enjoy,
Daniel Wanja.
Certified Flex 2.0 Developer.
Does a good idea make a good business?
On top of our Ruby on Rails consulting work we would like to create a small internet “service” business. Something like time.onrails.org but more fleshed out and supporting paying customers. We are bringing on board Solomon White, which is an awesome Ruby on Rails developers, to help out. So the other day we met and threw out some ideas of project we would consider doing. I think we came with a bunch of great ideas that each on their own could support a nice business or at least would be fun to develop. Often the feeling is that sharing these ideas would give away the “magic” ingredients that would make the new venture a success, that competition would outrun us and they will be first and take the whole market. I don’t believe so. A very close friend created a spectacular Java/.Net integration framework. He is adamant about not revealing too much on how he created it or even that he created it. The result is that potential customers don’t “just” find him as they don’t know that a solution to their problem is out there, and he must convince them really hard that he has the solution, and sometimes that they have a problem. In other scenarios a ‘surprise’ announcement, like Apple masters so well, has certainly a great impact as that creates lot’s of buzz on the net and in the news. The reality is that we don’t have Apples audience and no one is expecting a ‘surprise’ from us. I don’t think that they are not many great ideas worth keeping secret Rather find a problem or need and make sure you create an awesome solution addressing it. While you create it, talk about it, spread the word, gather feedback, talk about the technical challenges you encounter, feel the interest that’s out there. Then deliver. And deliver something exceptional …sounds familiar? Well that concept is not invented here, but if we shine at taking one of “our” ideas, and providing an exceptional implementation I believe we can attract many users and create a nice business out of it.
So the steps in the process becomes something like this:
1. Investigate ideas (that’s where we are at)
2. Choose idea.
3. Define project
4. Implement and spread the word.
6. Go live
7. Adapt and Improve
Currently we are in the “investigation” phase for several of these ideas. In other words we are coding and having fun and testing out different things. So here is the list of our killers ideas (in no specific order):
RailsLogVisualer plug-in: Realtime and aggregated log visualization of your Rails application. At the end of last year I wrote an offline Rails Log Visualizer. It’s pretty basic but provides some interesting information about the different applications we have in production. While writing it I realized that it would not be too difficult to have a plugin that would collect and aggregate request data and be able to provide information on the specific controllers and actions of the application. Of course it would require to support clusters of Rails applications. This plugin would provide a nice drill-down approach to the log data analysis which differs from a more traditional log analysis approach. For now, check out Geoffrey’s article on how to add Rails support to Mint for a nice way to analyze your log data on a deployed server.
ScrumPlan: An Agile Project management tool. I still do tons of enterprise work, and I really like how Scrum brings teams together. Scrum is very simple and a spreadsheet can be sufficient to get started, but I see the need for a simple dedicated tool to support the different activities that is simpler, more efficient and elegant than the existing tools out there. Lee is not too hot on this idea as we don’t use Scrum on our small projects.
FlexTester: An automation/regression tool for Flex. A large part of this testing tools would be in Flex, but the tool would have a server side part that is written in Ruby on Rails to keeps track of tests runs, to drive continuous integration and so forth. Flex is not directly related to Rails but I also do a lot of Flex work. I just think it’s a very nice way to create an UI, although in many case RJS does the trick as nicely and is “more” conventional. Flex is appropriate for enterprise applications (with many screens, many developers, lots’ of functionality) and Adobe just added some framework level way to record and playback user events (see the mx.automation package). There is currently one very expensive tool out there to create regression tests for Flex. Another more affordable one would be welcome. I started playing with the mx.automation framework and I am evaluating the effort implementing such a tool.
TimeOnRails 2: We have several hundred registered users (858 today) for time on rails and many use it on a daily basis. We received great feedback and also improvement requests. We use it our-selves on a daily basis and see many ways we want to improve and make it even more useful, especially on projects with multiple team members. Rather than just fixing the current code based which was implemented during the pre-RESTFull area, we want to rewrite it from the ground up. Note if we don’t select that idea, I will need to fix promptly several small issues on time.onrails.org.
RailsCloud: Rails hosting on a cloud. Ways to deploy or scale you Rails environment at the click of a button…This would leverage Amazon’s EC2.
S3Backup: Backup to S3 with a twist!
MySyder: The last year we worked in the eCommerce field. It’s pretty amazing what’s going on in this field, and there is the need to provide better tools for vendor and online stores. As part of “investigating” this idea we defined a subset of functionality related to “watching specific html pages” that we can turn into an online service or product by it’s self.
As you see we’ve got many ideas. I like Solomon’s way of looking at these ideas…“Which one we do first?” … More on that in the future.
RailsLogVisualizer: now open source and 6 x faster.
The Project Home Page is http://railslogvislzr.rubyforge.org/
The project is at http://rubyforge.org/projects/railslogvislzr/
Enjoy!