[ANN] Dr Nic’s Magic Models 0.8 - Validate Anything, Anytime, Anywhere
Ladies and Gentlemen, welcome one and all to the greatest Magic Show in Programming. If you bought free tickets to the last show, then you’ll be prepared to pay double for this show because its twice as good. Magic Models provide virtual validations on all database constraints!
In the first run of the sell-out Magic Models - “I can’t believe its an ActiveRecord” - Super Show - you were amazed as we stripped away the necessary essentials of an ActiveRecord - right in front of your eyes - the necessary became unnecessary.
We removed the validates_presence_of validations… and the Magic Model still validated.
We removed the has_many, belongs_to, and has_many :through associations… and the Magic Model still associated.
We removed the actual class definition itself - the very thing that provides the ActiveRecord CRUD layer… and the Magic Model still CRUDded.
You applauded loudly, and then walked out the front door surruptitiously ignoring the donation jar.
Today. Ladies and Gentlemen, I have removed the donation jar entirely so as to not distract your singular focus on the All New Magic Show!
Drums rolling in the background…
Let us start with a humble, unassuming database schema. Today’s schema syntax of choice? SQL.
CREATE TABLE `groups` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL UNIQUE, `description` varchar(50) default NULL, `some_int` integer default NULL, `some_float` float default NULL, PRIMARY KEY (`id`) ) TYPE=InnoDB;
The first change to note, is that all Magic Models and their associations are now being generated at startup time, and not dynamically.
>> ActiveRecord::Base.send :subclasses
=> [CGI::Session::ActiveRecordStore::Session, Group]
This is the current solution to supporting the :include option on find calls. Debate the pros/cons of this on the forum. It may be helpful for the various individuals trying to get Magic Models working with Streamlined.
Now… the magic!!! Watch carefully…
>> g = Group.new >> g.name = "x" * 51 => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" >> g.valid? => false >> g.errors.full_messages => ["Name is too long (maximum is 50 characters)"]
Crikey! That’s a beauty! That name is just too big for the database and boy does the validation automatically tell you that. Fantastic isn’t it!?
Ok, that’s enough Steve Irwin impressions.
>> g = Group.new >> g.name = "x" * 50 => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" >> g.valid? => true
Good.
Ok, more tricks… more drumrolls…
>> g.some_int = 99.9 => 99.9 >> g.some_float = "string" => "string" >> g.valid? => false >> g.errors.full_messages => ["Some float is not a number", "Some int is not a number"]
Tada!!!
And now for the final Virtual Validation magic trick… I draw your attention to the SQL: the name field is UNIQUE. Could the magic models… could they… no… maybe? Oh maybe they could support validation over unique fields?!?!?!
100 dancing girls and guys in silver spandex appear on the stage. Of course, more drums are rolling…
>> g = Group.new
=> #<Group:0x3884eb8 @attributes={"name"=>"", ... >
>> g.name = "test"
=> "test"
>> g.save
=> true
>> g2 = Group.new
=> #<Group:0x3884eb8 @attributes={"name"=>"", ... >
@new_record=true>
>> g2.name = "test"
=> "test"
>> g2.save
=> false
>> g2.errors.full_messages
=> ["Name has already been taken"]
Dr Nic takes a bow and is escorted off by his 100 dancers and 3 large elephants that turned up late.
Installation
gem install dr_nic_magic_models
The at the top of your Ruby script or at the bottom of your Rails’ environment.rb file, place the line:
require 'dr_nic_magic_models'
Epilogue
Matthew Painter made this possible. He is the author, producer, and cheer leader for this release. Whilst I was fart-arsing around writing Dr Nic’s GrandCivs, and he was doing something more important - making the Magic Models the ultimate magic show in town. And he has a funky website with a draggable background.
The original ideas for the extended Virtual Validations came from Red Hill Consulting: though again it was Matthew who did the work to integrate it into the Magic Models.
The whole of Magic Models architecture has been refactored. Matthew did that.
My 2+ gig of Gmail account filled with diff files. Matthew did that. You get the picture. Thanks Matt!
Anything, Anytime, Anywhere
“Anything, Anytime, Anywhere” was the slogan of the Goodies - a British TV show that was rerun over and over again after school in Australia. Their fame amongst school kids in the 70s and 80s, gives them Rock God status amongst midaged Australians today. They toured Australia in 2005 with 13 sell-out shows. I didn’t get tickets. If you did get tickets, I don’t want to know about it because I won’t talk to you.
[Trick] Natural language DSL in Ruby
Ever tried to explain DSLs (domain specific languages) to someone, so that they know how wonderful Ruby is, and just run out of useful examples? Try this piece of Street Magic on them…
The effect
See if your unsuspecting friend can figure out what this code will do. If they can, then say, “That’s because you are a domain expert in English. Good for you. Now use Ruby you Java boy.”
>> I.say "I love the Ruby language" You said, 'I love the Ruby language'
Cool, yes? Yes.
How this trick works
To set this up for your unsuspecting Ruby noob, type the following into your console/irb:
>> class I; def self.say(text); puts "You said, '#{text}'"; end; end
=> nil
Now you have a constant I upon which you can call class methods.
In long hand, this is:
class I
def self.say(text)
puts "You said, '#{text}'"
end
end
Create other pronoun classes, such as You, Everyone, etc and give them methods representing verbs, such as say, said, want_to.
For example,
class You
def self.cannot(action, target)
puts "Didn't your mother tell you never say never? Of course you can #{action} #{target}"
end
end
Which delights us with:
>> You.cannot :learn, "Ruby" Didn't your mother tell you never say never? Of course you can learn Ruby
“I still don’t know what a DSL is”
That’s unfortunate for you.
Exporting Netvibes bookmarks to Del.icio.us
For 12 months I’ve been using Netvibes to store bookmarks. A few weeks ago I started using Del.icio.us, which is also integrated into Netvibes. Now I had two sets of bookmarks. That’s one too many. Time to retire the Netvibes bookmark module, but how do I migrate/export the netvibes bookmarks, and how do I upload them to Del.icio.us?
“How to export Netvibes bookmarks?”
Exporting Netvibes bookmarks is a major request on their forum, so here is the answer.
- Login to Netvibes
- Go to address: http://www.netvibes.com/modules/bookmarks/getUserBookmarks.php?nocache=0
- Save the XML as
netvibes_bm.xml
The XML should look something like:
<result> <link id="4401802" title=".htaccess generator" url="http://www.tools.dynamicdrive.com/password/" tags="unix"/> <link id="6444925" title="19 Rails Tricks Most Rails Coders Don't Know" url="http://www.rubyinside.com/19-rails-tricks-most-rails-coders-dont-know-131.html" tags="RoR"/> <link id="4436310" title="37signals - the tools we use ourselves" url="http://37signals.com/svn/archives2/the_tools_we_use_to_run_and_build_37signals.php" tags="business, ideas, RoR"/> ... </result>
Note that your Netvibes tags are included. These will be uploaded into Del.icio.us too.
“How to upload Del.icio.us bookmarks?”
Now you are ready to upload these bookmarks into Del.icio.us (or modify it yourself to upload it wherever you want). I’ve written a script to do this using the Ruby programming language (dowload and install instructions here). Why? Because it took 10 minutes to do so. Feel free to rewrite it if you really want, but it’d be quicker to install Ruby, run the script, and move on with your life
- Install Ruby
- Install Hpricot [1]: type
gem install hpricot(select the win32 version if you are on windows) - Download the netvibes_delicious.rb script [2]
- Change the
usernameandpasswordvalues in the script to your del.icio.us username/password. - Execute the script:
ruby netvibes_delicious.rb netvibes_bm.xml - The script will tell you how many bookmarks it will be uploading to Del.icio.us, and ask you to press return to continue. Press Ctrl-C to kill the script.
If you want to “test” the script first, create a copy of your netvibes_bm.xml file, and cut away all the <link ... > tags, except one or two. Check that the script works on these few bookmarks first, then rerun the script on the original file.
Now add the Del.icio.us module into Netvibes and remove the original Bookmarks module.
Tally ho.
[1] Hpricot is a brilliant library for parsing and processing HTML/XML data.
[2] The contents of the script:
['rubygems', 'hpricot', 'open-uri', 'net/https', 'cgi'].each {|lib| require lib}
# Netvibes bookmarks XML file
file = ARGV.shift
bookmarks = []
page = Hpricot(open(file))
page.search("//link").each do |link|
bookmarks << {
:title => link.get_attribute("title"),
:description => link.get_attribute("title"),
:url => link.get_attribute("url"),
:tags => link.get_attribute("tags").split(', ').join(" "),
:shared => "yes"
}
end
puts "Transferring #{bookmarks.length} bookmarks to Del.icio.us"
puts "Do it?"; gets
# Del.icio.us target for bookmarks
username = "" # your del.icio.us username
password = "" # your del.icio.us password
resp = href = "";
bookmarks.each do |bookmark|
begin
http = Net::HTTP.new("api.del.icio.us", 443)
http.use_ssl = true
http.start do |http|
pp bookmark
req = Net::HTTP::Post.new("/v1/posts/add",
{"User-Agent" => "drnicwilliams.com Netvibes to Delicious"})
req.basic_auth(username, password)
req.set_form_data bookmark
response = http.request(req)
resp = response.body
puts "#{Hpricot(resp).search('/result').first.get_attribute('code').humanize} -> #{bookmark[:title]}"
end
rescue SocketError
raise "Host " + host + " not accessible"
end
end
Foreign tourists to your websites (part 2)
As a follow-up to the recent “Spy on the Japanese” post, you might want a nice set of links for your visitors to translate your page sinto their language.
But, here are your requirements (I can read your mind, I’m a doctor):
- You know what countries visit your site, so you want to configure it yourself.
- Since it requires Javascript to be turned on for it to work, you don’t want the links to show if the visitor doesn’t.
Solution: create the links using Javascript.
To allow translations of your blogs/websites via Google Translation, add the following inline Javascript into the sidebar. It was designed for Wordpress - you may need to twiddle with the DOM elements created and/or CSS if it looks bad on your site.
The flags can be found at: http://www.famfamfam.com/lab/icons/flags/, and I’ve assumed you’ll store the png images in the /images/flags/ folder. If you store them somewhere else, change the images variable at the top of the script.
So, paste this script into your sidebar and you are saying “Aliens Welcome Here” [1].
<script>
// Each lang in an array: [google lang code, flag name, language name]
// Flags available at: http://www.famfamfam.com/lab/icons/flags/
var to_langs = [['ja', 'jp', 'Japanese'],
['de', 'de', 'German'],
['es', 'es', 'Spanish']];
var from_lang = 'en';
var images = '/images/flags/';
document.write("<li id='translation'></li>");
var liDiv = document.getElementById('translation');
var title = document.createElement("h2");
title.appendChild(document.createTextNode("Translation"));
liDiv.appendChild(title);
var ulDiv = document.createElement("ul");
liDiv.appendChild(ulDiv);
for (var i=0; i < to_langs.length; i++) {
var to_lang = to_langs[i][0];
var flag = to_langs[i][1];
var name = to_langs[i][2];
liDiv = document.createElement('li');
ulDiv.appendChild(liDiv);
liDiv.innerHTML = "<a href='#' onclick=\"location.href=" +
"'http://translate.google.com/translate?langpair=" +
from_lang + "&" + to_lang + "&hl=" + to_lang +
"&ie=UTF-8&oe=UTF-8&u='" +
" + encodeURIComponent(location.href)\">" +
"<img border=0 src='" + images + flag + ".png' /> " + name + "</a>";
}
var getme = "<a href='http://drnicwilliams.com/2006/08/30/foreign-tourists-to-your-websites-part-2/'>How to translate my site?</a>";
var getme_li = document.createElement("li");
getme_li.innerHTML = getme;
ulDiv.appendChild(getme_li);
</script>
[1] Americans mightn’t know that when foreigners visitor your country, we are presented with paperwork to fillout that refers to us as Aliens. Perhaps your government never watches its own Hollywood movies, but this isn’t the best phrase to use, I think. Not very welcoming.
[ANN] Spy on the Japanese Rubists
Their Ruby code is surrounded by a shrouded of Japanese symbols. You know there is gold in there, but its left to the reader to interpret the purpose of the article. Happy Japanese man? Cranky Japanese man?
The creator of Ruby is Japanese, the Rubist magazine is in Japanese, and a great many users of Ruby are Japanese, yet I can’t understand a word they are saying. That’s not their fault. It’s my French teacher’s fault.
Wonder no longer. Thanks to Google Translate’s Japanese to English translation and the Bookmarklet feature of Firefox (and other browsers?)
Drag this Bookmarklet into your links toolbar, and start spying on the Japanese.
Bookmarklet: Spy on Japanese
Want to spy on the Germans? Drag it again, and change the embedded url. Look for the langpair=ja&en and change ja to de. (Cheat: Spy on Germans)
Want to encourage our Japanese friends to spy on you? Perhaps add links on your pages for instant translations from English to Japanese (change ja -> en, and en -> ja), and change the hl=en to hl=ja.
<a href="#" onclick="location.href='http://translate.google.com/translate?langpair=en&ja&hl=ja&ie=UTF-8&oe=UTF-8&u=' + encodeURIComponent(location.href)">Translate into Japanese</a>
Test this here:
- Translate into Japanese
- Translate into German
- Translate into Spanish
Can someone tell me what Japanese characters I should use for this link?




