Bloated RailsConf Presentation Downloader 2

Posted by Lee Marlow Mon, 21 May 2007 22:49:00 GMT

I’ve updated my downloader from earlier to include all sorts of fancy options. It no longer requires wget, it just uses open-uri. It can give the files a fancy name. It can be told where to download the files to. It will skip files that won’t download for some reason. It will even butter your toast if you can find the correct command line switch.

It’s about 3 times bigger than the previous one. But maybe you can learn a little more about optparse, hpricot, file handling, and error handling along the way.

Here it is:

#!/usr/bin/env ruby

require 'optparse'

OPTIONS = { :Verbose => false,
            :Force => false,
            :DownloadDir => '.',
            :DescriptiveFilenames => true
          }
OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely, default #{OPTIONS[:Verbose]}") do |verbose|
    OPTIONS[:Verbose] = verbose
  end
  opts.on("-f", "--[no-]force", "Force downloads, default #{OPTIONS[:Force]}") do |force|
    OPTIONS[:Force] = force
  end
  opts.on("-d", "--[no-]descriptive", "Use long descriptive filenames, default #{OPTIONS[:DescriptiveFilenames]}") do |long|
    OPTIONS[:DescriptiveFilenames] = long
  end
  opts.on("-p", "--path PATH", "Path to download to, default #{OPTIONS[:DownloadDir]}") do |path|
    OPTIONS[:DownloadDir] = path
  end
  opts.on_tail("-h", "--help", "Print help message") do |help|
    puts opts
    exit
  end
end.parse!

require 'rubygems'
require 'hpricot'
require 'open-uri'
require 'fileutils'

BASE_URL = 'http://www.web2expo.com'

def log(str)
  puts str if OPTIONS[:Verbose]
end

def download(href, filename)
  url = "#{BASE_URL}#{URI.escape(href)}"
  download_file = File.join(OPTIONS[:DownloadDir], filename)
  if OPTIONS[:Force] || !File.exists?(download_file)
    log "downloading #{File.basename(href)}..."
    begin
      File.open(download_file, 'w') { |f| f.write(open(url).read)}
      log "\tsaved as #{download_file}"
    rescue Object => e
      FileUtils.rm(download_file)
      $stderr.puts "ERROR downloading #{url}: #{e.message}"
    end
  else
    log "skipping #{File.basename(href)}... already downloaded as #{download_file}"
  end
end

FileUtils.mkdir_p(OPTIONS[:DownloadDir])
h = Hpricot(open("#{BASE_URL}/pub/w/51/presentations.html"))
h.search('div.presentation').each do |presentation_node|
  href = presentation_node.at('a[@href^="/presentations/rails2007/"]')[:href]
  if OPTIONS[:DescriptiveFilenames]
    name = presentation_node.at('b a').inner_text.strip
    text = presentation_node.inner_text
    speaker = text[/Speaker\(s\):\s+(.*)\s*$/, 1]
    date = Date.parse(text[/Presentation Date:\s+(.*)\s*$/, 1])
    filename = [speaker, date, name, File.basename(href)].compact.map { |s| s.to_s.strip.gsub(/[^\w\.]/, '_').squeeze('_') }.join('-')
  else
    File.basename(href)
  end
  download(href, filename)
end

Download RailsConf 2007 Presentations 5

Posted by Lee Marlow Mon, 21 May 2007 18:27:00 GMT

Updated: Now more bloated!

Run this to get the RailsConf 2007 presentations:
#!/usr/bin/env ruby

require 'rubygems'
require 'hpricot'
require 'open-uri'

base = 'http://www.web2expo.com'
h = Hpricot(open("#{base}/pub/w/51/presentations.html"))

h.search('div .presentation > a[@href^="/presentations/rails2007/"]').each do |a|
  url = "#{base}#{a[:href]}"
  if File.exists?(File.basename(url))
    puts "skipping #{url}... already downloaded"
  else
    puts "downloading #{url}..."
    `wget --quiet #{url}`
  end
end
I might clean it up more later to name the files better and not use wget, but this was quick and easy... not to mention a way to use everyone's favorite parsing tool: Hpricot.

Will Marcel Molina Steal Matz's Ruby Super Powers 3

Posted by Lee Marlow Fri, 18 May 2007 18:02:00 GMT

I didn’t start watching Heroes until after I heard Rich Kilmer and Marcel Molina talking about it while putting the badges together for RubyConf 2006 in Denver.  Had I watched it before maybe I would have been a little scared of Marcel (Sylar), but he was very nice and didn’t seem like a threat to the Ruby world at all.

So, why be scared of Mr. Molina? You be the judge.

class MarcelMolina
  include Heroes

  def <=>(other_hero)
    other_hero.name == 'Sylar' ? 0 : 1
  end
end

== # => true

RailsConf 2007 - Day 2 1

Posted by Daniel Wanja Fri, 18 May 2007 16:35:00 GMT

Note: Check out the RailsConf Wiki and the presentation page

Chad Fowler is starting the keynote introduction. 1600 developers are at the keynote. He makes a passionate speech about how Rails is changing how we think about software and how Rails impacted the industry. An now Rich Kilmer introduces the person that introduced him to Textmate: DHH.

A peek at Rails 2.0

Celebrating what we have

  • > 1 million downloads
  • Hundreds of plugins
  • ~10k people on rubyonrails-talk
  • He asks who is getting paid in one form or another using Rails and a large part the participants raise their hands. ( Books: many Rails books in many languages. Surpassed PHP, Perl and Python (source O’Reilly Radar).
  • http://workingwithrails.com/ indicates over 100 countries where people do Rails.
  • IDE: CodeGear, Textmate, NetBeans, JetBrains, Aptana

Rails 2.0

  • It’s not gonna change everything you know, it’s gonna be humble.
  • No new ‘great’ idea.
  • The experiment worked! (RESTFul resource)
  • The world of resources is a better, greener place.
  • Rails 2.0 will focus more on the REST convention
  • Routes
map.namespace(:admin) do |admin
  admin.resources :products,
    :collection => {:inventory => :get},
    :member => {:duplicte => :post},
    :has_many => [:tags, :images, :variants],
    :has_one => :seller
end
  • David now demos the new scaffolding that use the resource approach of working with things.

./script/generate scaffold persone name:string create_at:time

* He adds new format format.csv to support exporting as comma separated text. You can easily connect to this services:
require 'active_resource'
class Person < ActiveResource::Base
  self.site = "http://localhost:3000"
end
p = Person.find 1
  • Beyond CRUD you can custom methods, Person.find :all, :params => {:name => ‘d’}
  • This all works today.
  • Action Web Service is no longer service with Rails 2.0. ActiveResource is.
  • Friends and allies: Ajax, REST, Atom, OpenID

9 other things I like about rails 2:

1) Breakpoints are back (ruby_debug)

2) HTTP Performance

<!-- :cache => true
     gzips all javascript and stylesheet in one file 
     i.e. prototype, css get zipped down to 35K from 200k
-->
<%= javascript_include_tag :all, :cache => true %>  
<%= stylesheet_link_tag :all, :cache => true %>  

3) Query cache. DHH loves free performance

4) action.mime_type.renderer
people/index.html.erb
people/index.xml.builder
people/index.rss.erb
people/index.atom.builder
def index
    respond_to do |format|
        format.html
        format.xml
        format.rss
        format.atom
    end
end

5) config/initializers. One file per configuration in initializers folder

6) Sexy migrations (just nicer)
create_table :people do |t|
  t.integer :account_id
  t.string :first_name, :last_name
end
7) HTTP Authentication. authenticate_or_request_with_http_basic

8) The MIT assumption. ./script/generate plugin now generates a default MIT license file.

9) Spring cleaning. Deprecated features of 1.2 will be removed. In-place editor will be moved to plugins.

That’s pretty much it. Thank you.

Building Community Focused Apps with Rails by Dan Benjamin

Rails is the ideal platform for Web 2.0. Fast prototyping and proof of concept. Prototype becomes the product. Conducive to collaboration with developers and designers. Dan is going to talk about Cork’d. Currently 20000 users.

Make a Plan.

  • Treat your application like a product and your idea like a business. Just because it’s a good idea doesn’t mean it’s gonna be automatically successful.
  • Stay Agile. Resist big infrastructure.
  • Build the Right Team. Keep it light.
  • Determine Ownership.
  • Have a Revenue Stream (ads don’t count)
  • Focus on Simplicity. Don’t build features just because you think they are cool.
  • Don’t Release a Public Beta. They had two private betas. They learned from a handful set of people rather than from a large group.
  • Know Your Audience. Be your Audience

Build the App.

  • Think Like a Designer.
  • Consider the Fold.
  • Avoid Big Migrations. User entered data can be challenging.
  • Collaborate.
  • The Rails Layouts Makes Designers Happy.
  • Common Rails Collaboration Tools. Subversion, Capistrano, Campfire, Basecamp, Lighthouse.
  • Don’t Repeat Yourself: Use Plugins. acts_as_authenticated, attachment_fu, acts_as_taggable, exception_notification, open_id_authentication, ymlr4r geocode
  • Take “Code Vacations”

Get Noticed

  • “It’s Google’s World, We Just Live in It.”
  • Use Smart URLs. /wine/view/5748, /authors/danbenjamn
  • Leverage Markup. Google reads metatags.

Recruit Members

  • Make It Obvious and Easy to Signup
  • Ask Only for What’s Truly Necessary
  • Ask for Everything but Require (Almost) Nothing
  • Limit Non-Members

Keep Them Coming Back for More

  • Make Frequent Improvements
  • Respond Positively to Your Members
  • Create A Developer Network
  • Share Your API
  • Find Good Partners
  • “If You Do Things Right, People Won’t Know You’ve Done Anything At All.”
  • Just Ship It

How We Used Apollo and Rails to (start to) Build an Agile Project Management App by Christopher Haupt and Chris Balley

They are part of Adobe’s Consumer Hosted Applications and Online Services group. They use whatever technology is right for the job, Flex, Rails and dozens of other technologies. They use Scrum and are geographically dispersed teams, in Germany, India, US.

Why Did We Choose Apollo and Rails?

  • Learning Exercise
  • Offline Support
  • Maturing Tools
  • Leverage our Rails Experience
  • Cross Platform
  • Installers

Why not AJAX?

  • Offline and Partially Connected
  • File System Access
  • Drag and Drop with Native OS

Now they are demoing Maptacular, an Apollo applications.

Combining Apollo and Rails: Communication

  • Flash Side
    • AMF
    • SOAP
    • REST <== they used that
  • HTML Side
    • AJAX techniques
  • Hybrid
    • Ue DOM bridge to use the one you are comfortable with.

Combining Apollo and Rails: Quirks

  • Flex’isms
  • RESET can be a pain
    • Use _method hacks for PUT, DELETE, HEAD
    • Pass a body on everything other than GET
  • Some HTTP headers can’t be used, or problematic on a GET
  • HTTP Status codes not accessible
    • Use URLoader to get HTTP Status Codes
  • dasherize-is-unhealthy-to-your-actionscript-code
  • Migrating to newer Apollo Builds
    • ApolloApplication .vs. Application (for transparency)

Now they move on to Code Snippets. The sample code can be found on the Apollo Labs.

  • Online/Offline (Event.NETWORK_CHANGE). Notifies if network change but doesn’t tell if network is up or not. Solution: use URLoader to ping the network (they ping google.com)
  • Video Capture, File IO, Doing your own Chrome

Chris now demonstrate some community create applications.

RailsConf 2007 - Day 1 3

Posted by Daniel Wanja Thu, 17 May 2007 16:04:00 GMT

Here we go, RailsConf 2007, has started. It’s bigger than ever, more tracks, more sessions. This is the first day where they provide full or half-day tutorials sessions. I will try to cover the different sessions I will attend so stay tuned.

Today I will attend: “Scaling a Rails Application from the Bottom Up.” and “Harnessing Capistrano.”

Scaling a Rails Application from the Bottom Up. by Jason Hoffman

Jason Hoffman, CTO of Joyent. Did also form Textdrive.

Six part presentation:

I. Introduction and foundation II. Where do I put stuff III. What stuff? IV. What do I run on this tuf? V. What are the patterns of deployment? VI. Lessons learned

His presentation will answer the following questions:

  • What is a “scalalble” application?
  • What are some hardware layout?
  • Where do you get the hardware?
  • How do you pay for it?
  • Where do you put?
  • Who runs it?
  • How do you watch it?
  • What do you need relative to an application?
  • What are the commonalities of scalable web architectures?
  • What are the unique bottlenecks for Ruby on Rails applications?
  • What’s the best way to start so you make sure everything scales?
  • what are to common mistakes?

Maybe it’s a little early, or I am not awake, but the talk seems a little slow. But Jason seems to do a good job at describing how the different people (developer, sysadmin, ...) see scalability.

Ease of management is on log scale. It’s not just a Rails issue. A $5000 Dell 1850 costs $1850 to power over 3 year.

This is a really good presentation from a point of view of what is involved to build data center. I should have read better the description of the presentation.

So I am going to move over to Thomas Fuchs presentation:

Is JavaScript Overrated? Or: How I Stopped Worrying and Put Prototype and script.aculo.us to Full Use by Thomas Fuchs

I am just tuning in to his presentation and he is showing of how to use selectors with Prototype.

DOM traversal:
$('blech').previous('ul').down('.somesuch',2)
$('homo-sapiens').descendantOf('australopothecus')
Element methods:
$('a_div').update('blah').show().setStyle({opacity:0.5});
$('myform').focusFirstElement();
$('person-example').serialize();
Element.addMethods('form') {
  valid: function(element) {
       // code to valid form
  }
}
What’s new in Prototype 1.5.1:
  • speedier $$
  • CSS 3 Selectors
  • $(‘form’).request()
  • String .includes .times .toPaddedString(8,2)
  • JSON support i.e. new Date().toJSON();
  • $(‘blah’).firstDescendent()
  • throw $continue deprecated use “return” instead
  • Safari issues fixed
  • YAML compatible

DOM, Events, Forms, Position:

  • new Element(tagName, attributes);
  • $(‘blech’).insert(html|object, position)
  • $(‘blech’).wrap(‘span’);
  • $(‘country’).setValue(‘AT’);

Function.prototype: curry(), wrap(), defer(), delay() Q: When is the next release of Prototype? A: When it’s ready.

A 10 minute break now, the Thomas is going to present Scriptaculous Effects.

script.aculo.us adds advanced User Interface interaction to the DOM. Extracted from Real-World applications. Started with Fluxiom. The two main parts are Visual effects and Drag&Drop. Today we will only look at the Visual Effects. They are other parts such as Autocompleter, In-Place Editor, Slider control, DOM Builder, and Unit testing. They won’t be more advanced components.

Effects engine: the ideas behind the engine is timeline based animations.

Core Effects:
  • Effect.Move
  • Effect.Opacity
  • Effect.Highlight
  • Effect.ScrollTo
  • Effect.Morph // 1.7+
  • Effect.Parallel

Based on the Effect.Base.prototype class. Effect life cycle: intialize(), setup(), update(), finish(). Each frame calls update().

Effect.DefaultOptions = {
    transition: Effect.Transitions.sinoidal,
    duration: 1.0,
    fps: 100,
    sync: false,
    from: 0.0,
    to: 1.0,
    delay: 0.0,
    queue: 'parallel'
}

Morphing: came out with Scriptaculous 1.7.

$('mydiv').morph('font-size:20px; color:"#abcdef");
$('mydiv').morph('warning'); //limited to top level classname
TimeLines:
new Effect.Blah('element_2')
new Effect.Blah('element_2', {duration:0.6, delay:0.3});
You have to be careful with effects created that will run in parallel as the javascript engine are not multi-thread. Better solutions is to use queues:
new Effect.Blah('element_1', {queue:'end'});
new Effect.Blah('element_2', {queue:'front'});
and use scope:
new Effect.Blah('element_1', {queue:{scope:'blech'}});
new Effect.Blah('element_2', {queue:{scope:'blech', position:'end'}});
new Effect.Blah('element_3', {queue:'front'});
Utilities:
Element.toggle('element', 'blind');
Element.tagifyText(element);
Element.multiple('element', Effect.Fade, {speed:0.05});

Do it yourself: Thomas now shows how to create an Effect programatically.

Future features:
  • Sound without Flash (it’s already in the beta release). Sound.paly(‘sword.mp3’). It uses native sound implementation with Quicktime as fallback.
  • Adjust to new Prototype features. $(‘blech’).fade(); $(‘blech’).slowlyReveal();

Part IV: Testing

Thomas is flying through testing…
  • assert(true)
  • assertEqual(expected, actual)
  • assertEnumEqual(expected, actual)
  • assertNotEqual(expected, actual)
  • assertMatch
  • assertIdentical
  • assertNotIdentical
  • assertType
  • assertRaise
  • assertRespondTo
  • assertVisible(element)
  • assertNotVisible(element)
  • info(message)

Mostly unit testing, but some functional testing is available. Most assert take a message. I.e. assertXYZ(params, message)

  • wait(milliseconds, method) // should be last statement in test, but can be nested.
  • rake test:javascripts (browser will popup). Done with the javascript_test plugin. Launches the web server (WEBrick), then controls the browsers (Safari, Firefox, IE), the browser then calls the web server, and list the results (SUCCESS, FAILURE, and ERROR)
Resources:

JRuby talk by Charles Nutter and Thomas Enebo

(note taken by Robert Hall, thanks man!)

  • 1.8ish—based on Ruby 1.8.5
  • Gems 0.9.1 is pre-installed
  • Partially compiled—about 80% of Ruby code compiles…rest is run in JIT mode
  • Ruby 1.8 strings supported. Works with ActiveSupport::MultiByte
  • Ruby 2.0 String support coming
  • Most Ruby apps should work on JRuby —most gems just work —Red Cloth, Blue Cloth —Hpricot
  • Typical Rails commands just work
  • ports: Mongrel ported, Hpricot ported, RMajick in progress
  • Ruby thread API supported —native-threaded 1 JRuby thread=1 system thread —supports thread pooling
  • performance comparable to C Ruby impl —Rdoc has issues —CLI performance slow
  • JDBC support strong —mySQL support strong —some postgres issues —some Oracle users —many others
  • ActiveRecord JDBC
  • No native extension support
  • Goldspike—JRuby deployment tool —Rails plugin for building WAR files —app server agnostic —Can be deployed to Java app server as WAR file
  • Deployment—MOngrel supported..some issues (forking, process management doesn’t work)
  • Access to Java EE features (JMS, JPA, JTA)
  • Java libraries can be wrapped
  • Coming soon —A Grizzly/GlassFish V3 option —Lightweight, gem-installable like Mongrel —Concurrency, pooling mulit-app like WAR
  • Mephisto demo
  • Main idea—- Ruby as the programming language, Java for the platform and libraries
  • Best of all worlds —Ruby or Rails as the appl layer —Java libraries alone or as ported/wrapped gems -Java based services-legacy app integration —The JVM
  • Acceptable to today’s enterprise —Java to ‘them’, Ruby to you
  • Calling Java from Rails demo —RSS reader demo..calling Java library from Rails code
  • Tools— Textmate, Emacs, Vi(m), notepad —missing some features —code competion? —jump to declaration? —rename variables? —popup Rdoc?
  • Presenters claim Best Ruby IDE Available is NetBeans (milestone 9) —code completion —smart syntax highlightings (for Ruby code, RHTML files, etc) —Rdoc support
  • Demoed a cool Ruby shell like IRB implemented in Swing..built into NetBeans
  • Jruby 1.0 almost ready

LUNCH: will be back at 1:30pm

Harnessing Capistrano by Jamis Buck

Jamis will focus Capistrano 2.0 today. Some things will not be backward compatible with Capistrano 1.0.

His slides are online at http://presentations.jamisbuck.org/railsconf2007/.

Lee's RailsConfPlan at MyConfPlan

Posted by Lee Marlow Wed, 09 May 2007 20:10:00 GMT

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!

Posted by Daniel Wanja Wed, 09 May 2007 18:59:00 GMT

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? 12

Posted by Daniel Wanja Wed, 09 May 2007 14:31:02 GMT

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.

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.

UserController#forgot_password
  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 
  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_password
  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"    
  end

The email is simply send using the following ActionMailer.

UserNotifier
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
end

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

Posted by Solomon White Fri, 20 Apr 2007 14:54:00 GMT

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

Posted by Daniel Wanja Tue, 06 Mar 2007 18:36:30 GMT

20070306_signup_errors.jpg

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
end

If 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 &gt;&gt;" 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 &amp;&amp; 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.

Older posts: 1 2 3 4 5 6