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? 13
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.
class ForgotPassword < ActiveRecord::Migration
def self.up
add_column :users, :reset_password_code, :string
add_column :users, :reset_password_code_until, :datetime
end
def self.down
remove_column :users, :reset_password_code
remove_column :users, :reset_password_code_until
end
end“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.
def 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
endSend 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.
def 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"
endThe email is simply send using the following ActionMailer.
class 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}"
end
protected
def setup_email(user)
@recipients = "#{user.email}"
@from = "admin@myspyder.net"
@subject = "[myspyder.net] "
@sent_on = Time.now
@body[:user] = user
end
endAnd the view for the UserNotifier is the following
<%= @user.email %>,
You can reset your password by using the following link <%= @url %>
Thank your for using MySpyder.netTextMate 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. 7

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 5
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
worbserviceNote 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. 12
| 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 |
./script/generate scaffold_resource watchimport 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)Certified Flex 2.0 Developer. 16
Does a good idea make a good business? 9
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!
The Rails Edge Conference in Denver - Day 3
I am a bit late (20minutes) to the conference as I had an iChat with my nieces that turned 3 today.
THE RAILS TIMES by Mike Clark and Bruce Williams
- HABTM Ousted in favor of Rich Models using has_many :through.
- Many deprecations telling you how to prepare for Rails 2.0.
- Routes get named.
- Extra: Ruby generates javascript. page[:tags].reload # reload _tags.rhtml partial.
- Serial(ization) Killers At Large: YARML, XML, JSON
- RSS is the next big thing: render_rss_feed_for(@people, options)
- The future is CRUD: ruby script/generate scaffold_resource article. map.resources :articles
- Conventions Flourish: see simply_helpful. form_for @person do end
- BULLTIN: Apps respond-to Clients: respond_to do |format| format.html, format.js, format.xml, format.yaml. Custom format can also be added.
- CORBA? RMI? No, ActiveResource!: class Person < ActiveResource::Base
- Security Alert! Parameter Filtering – filter_parameter_logging :password, :login, :user
- Installation Typo Triggers Global App Meltdown: rake rails:freeze:gems
- Manking Attacked by Mongrel: gem install mongrel
- Tomorrow’s Edition? : Rails 2.0? REST?
This is an awsome talk where Chad is going into the impact that a RESTFul approach has on your development and how to write your application using the new named routes and RESTfull controllers.
Streamlined by Justin GehtlandJustin goes through many of the options on how to manipulate declaratively a Streamlined driven UI.
Road map:
- 0.0.6 new look (soon)
- 0.0.7 control types for fields
- 0.0.8 plugin instead of generator
- 0.1 99% rcov, compatibility
- visual configuration
- declarative tabbed ui 0.0.8?
- generated columns sortable
- context specific ui (different for list, show , edit…)
- rich text editor (TinyMCE)
Start Early deploying your applications. Find all the “interesting” deployment problems up front. You’ll know how to do it when the times comes. You’ll get into the deployment rhythm.
How to do it: not using WEBrick, CGI, FastCGI…but proxy to Mongrel (ya-huh!). Front End use Apache, Lighttpd, Pound, Pen, or hardware load balancer. Use Capistrano. The Golden Path assumes Capistrano, Unix (NOT Windows), subversion. Apache 2.2.x (myproxy balance), Ruby Termios Library, MySQL 5. Duncan then went on to a live demo, connected to his Subversion repository in Portland using the Hotels network deploying to an EC2 (Amazon Elastic Computing Cloud) . So pretty gutsy demo but the demo went on pretty well.
CONFERENCE CONCLUSION!Awesome conference, well worth the money. Not only was it well organized but the talks where just loaded of useful information. Thanks to all the presenters!