I don’t know about you, but taking a look at a new framework
is a daunting task. Particularly if there are code generators and
multiple directories involved. You don’t know what is
assumed, and what is required. Sure, the
videos make it look easy,
but somehow the person making the presentation always seems to
already know all the answers; they know exactly where to put every
file, the syntax of every command and statement, and have a
detailed knowledge of all the relevant class libraries.
What I like about PHP, JavaScript, Python, Perl, and a number of
other languages is that you can start with a real example that you
can understand that fits comfortably in a single text file.
For this reason, the first task I take when approaching a new
language or framework is to distill down an equally simple example
to it’s essence. Only after I ‘grok’ the
example, do I then move on to bigger and better things. In
this case, that presumably involves splitting the file up into
chunks, seeing where the chunks belong, and then adding test cases,
function, html pages, etc.
Herewith is a
single example, annotated stanza by stanza below. Note
that this example is designed for Ubuntu Linux, some small
modifications may be required to run in other environments.
mysql function
Ruby makes it easy to interact with the command line, piping in
input, capturing output and the like. But since we are going
to interact with mysql three separate times in this script,
let’s make it even easier by defining a function that accepts
two parameters: the first is the options to be passed
on the command line, and the second is the stream of
data to be piped in.
def mysql options, stream
IO.popen("mysql #{options}", 'w') { |io| io.puts stream }
end
This function makes use of a number of Ruby idioms. First,
there generally is no need to enclose parameters in parentheses
unless you really want to.
IO.popen opens a pipe, in this case for
writing. The name of the “file” is simply the
command to be executed. Note that double quoted strings
enable you to make use of embedded Ruby, which I use to insert the
options into the command.
While IO.popen can be used as a traditional
function, returning a stream that you can write to and ultimately
are responsible for closing, I’m making use of another idiom:
passing a block to the function. IO.popen will
bind the file handle to the argument you specify, and take care of
ensuring that the pipe is closed properly when you exit the scope
of the block. Sweet!
create database
Now, lets make use of this function, first as root.
mysql "-u root -p", <<-END
drop database if exists weblog_development;
create database weblog_development;
grant all on weblog_development.* to #{`id -un`.chop}@localhost;
END
Here we are invoking mysql, specifying user as root, and
requesting that there be a prompt for the password.
The stream of commands is passed in what is commonly known as a
here document. Note that embedded Ruby is also
available. In this case, we shell out to the command line and
get the name of the user running the script. The result is a
string, and therefore we have access to all the normal methods that
are available on a string. In this case, we wish to chop off
the trailing newline.
On non-Unix based systems, you may need to substitute another command,
or simply hardcode your user id.
Create table
Now, create a table named entry with id,
title, updated_on, and
content columns. The suffix _on is
a little Rails magic that ensures that the field will get
initialized to Time::now. I haven’t
decided whether that one line of code savings is worth it for my
application, but for now, I’m including it in the demo.
mysql "weblog_development", <<-END
drop table if exists entries;
create table entries (
id int not null auto_increment,
title varchar(100),
updated_on datetime,
content text,
primary key(id)
)
END
Pretty standard SQL stuff, except for the fact that the way you
specify the notion of auto_increment appears to vary
across databases. Grrr...
Requirements
Next we pull in the necessary Rails functionality
require 'rubygems'
require_gem 'activerecord'
Not much to this. Note that Kernel::require
is simply a function (don't let the absense of parentheses fool you),
and can be invoked any place in a program — similar constructs in
other languages must appear at the top. The rubygems library includes
a Kernel::require_gem function, which is used in the
next statement.
The net effect of all this is that one can readily extend the Ruby
language with domain specific grammar. Rails makes extensive use of this in
ActiveRecord, though this isn't demonstrated in this example.
Pretty straightforward, particularly as this call uses named
parameter association. Note that the value you need to
specify for the socket may vary across systems. I found the
correct value for Ubuntu systems
using Google.
Generating Code
Now, lets generate code for the entries table:
class Entry < ActiveRecord::Base
end
Not much there, eh? That’s because
ActiveRecord::Base already knows about your database,
and when it sees a class named Entry, it looks for a
table named entries and infers all it needs to know
about what attributes it needs to create.
First Post
Now lets create and save a row:
post = Entry.new
post.title = "First post!"
post.content = "Hello from Ruby on Rails!"
post.save
Again, not much there. Create a new entry. Set
title. Set content. Save.
Checking to make sure
There is an ancient Russian saying, “trust, but
verify”. Let’s check to make sure that mysql is
convinced that this data is there.
mysql "-t weblog_development", <<-END
select * from entries;
update entries set content='Right back-atcha from MySQL!';
END
We use the trusty mysql function we defined earlier, this time
passing the “-t” option (otherwise, mysql
“knows” that we are running it batch, and the output
isn’t quite as pretty). We select all from entries, and
sure enough, everything is there (see sample output below).
Just be doubly sure, we update the entry with some new text.
Full Circle
Now, lets make sure that Rails can retrieve this data from the
database.
puts Entry.find(:first).content
Find the first (and in this case, only) entry, get the content
from that entry, and put it to the screen. Again, nothing to
it.
Output
Here’s the output from running this application:
Enter password:
+----+-------------+---------------------+---------------------------+
| id | title | updated_on | content |
+----+-------------+---------------------+---------------------------+
| 1 | First post! | 2005-08-09 17:06:05 | Hello from Ruby on Rails! |
+----+-------------+---------------------+---------------------------+
Right back-atcha from MySQL!
If you want to try it for yourself, the
full script can be found here.
Cool! The RedHanded folk have been speculating about when you would pick up your namesake language and start running with it. In fact you can find some of their speculation about your doing this here: [link]
(the first two comments)
BTW: what do you think of Rails and Ruby now that you’ve gone through this exercise?
Since David’s gone all this week, I’ll pick up some of the Rails news, how about? Especially when the Rails news gets us back into hacking plain old Ruby code. As is the case with Sam Ruby, who’s tinkering with Rails outside of the...
I’ve been working with Rails heavily for about 9 days now on a pretty decent sized app and I have to admit it took me a day or two to feel comfortable with the directory structure and file layout (not just where the files are but from where and when they’re magically referenced/loaded). But right now, with the size of app I’m working with, it’s working very well. The basic set of learning you’ve illustrated here scales to at least medium sized applications with basic relationships between 10-20 entities. I don’t foresee any huge issues with more complex functionality or larger project size but I’ve never predicted “huge issues” very well in the past :)
What I’m trying to figure out now is how to compose multiple Rails directory hierarchies to run as a single app. I’d like to overlay routes/controllers, public files, models, helpers, and views. There’s things you need to figure out here that you wouldn’t have to, or that would be more obvious by following the code, if you were using an insigificant directory structure or simple, more explicit linkages between the parts of the app.
I’m not hating these trade-offs at this point but I’m still a bit sparkle-eye’d about working in this environment full time. I might hate it in a month but it doesn’t feel that way.
Note that Kernel::require ... can be invoked any place in a program — similar constructs in other languages must appear at the top.
Of the four languages you mentioned, require can be invoked anywhere in both PHP and Perl, I don’t know of an equivalent in JavaScript, and Python’s import can be invoked anywhere. I’m not an expert in all of these languages, but your statement doesn’t seem to apply to any of them. What languages are you talking about in which requirements must be appear at the top?
It’s one of Sam’s favorite marketing tricks. If none of the reader’s favorite languages require it, they relate ot to those languages and pat themselves on the back for being so clueful. If the languages they’re familiar with do require imports at the top, they’ve learned something in a non-condescending way. Building confidence, you see.
It’s one of Sam’s favorite marketing tricks. If none of the reader’s favorite languages require it, they relate ot to those languages and pat themselves on the back for being so clueful. If the languages they’re familiar with do require imports at the top, they’ve learned something in a non-condescending way.
;-)
I was primarily thinking of Java. From what I hear, some people still use that language.
Furthermore, I’ll wager that there are a number of Python programmers who don’t realize that they can import modules from any place other than the top of the file.
For simpler Ruby-Shell interaction you may also use system("open /file.txt; ...) on Mac OS X. But also see tech.rufy.com/entry/75 for yet another more sophisticated example of Ruby-Shell code!
Hey, its great to see you trying the Ruby waters. Welcome.
Just a small comment on the use of ‘require_gem’. You only need the require_gem command if you are explicitly loading a particular version of the activerecord gem. RubyGems allows you to have multiple gems installed and select from the available versions.
If you just want the latest version, just say “require ‘active_record'”, and the RubyGems system will do the rest. Note the use of the underscore. 'active_record’ is the file you wish to require, ‘activerecord’ is the package/gem name that contains the file named ‘active_record’ (along with a number of other files).
Sam Ruby szerint bár a Rails videók alapján azt gondolhatjuk, egyszerű a Rails fejlesztés, neki mégis hiányzik egy olyan dokumentum, mely egy egyszerű példaprogramon, nem szerteágazó kódfákon, generálásokat használva vezet be az alapokba. Blogjában...
I’ve been working with Ruby on Rails full-time for almost a year now, and this post scares me a little ;-) You’re meant to lie back and let Rails take the strain. I haven’t touched ActiveRecord::Base.establish_connection in tens of thousands of lines of commercial code so far. Getting to the crux of things is fine, but this might be riding a little bit close to the ground. It seems like getting to the crux of x86 development by writing straight into hex code rather than assembler :)
There’s a one to one correspondence between the parameters passed to establish_connection and the lines you put in config/database.yml.
I do, however, accept that different people are made comfortable by different things. Until I understand what is going on, I’m generally not comfortable letting go and allowing generators or wizards or frameworks to take over for me.
Yeah, I totally understand your opinion, Sam :) I guess I just like putting my feet directly onto Rails' ground rather than Ruby’s ground. Then again, I have always been a Rails first, Ruby second, kinda guy. No doubt this will change over time :)
Anyway, I’m ecstatic to have you over on this side of the water. Ruby has been lacking when it comes to some of the areas you specialize in.
Martin Fowler: Call Super [API design]"Call Super is a minor smell (or anti-pattern if you like) that crops up from time to time in OO frameworks."Martin Fowler: Using the Rake Build Language [ruby build tutorial]"Rake is a build language, similar...
For some additional context, from page 201 of Agile Dev:
“When we wrote the [example] application earlier in this book, we didn’t use the establish_connection() method. Instead, we specified the connection parameters inside the file config/database.yml. For most Rails applications this is the preferred way of working. Not only does it keep all connection information out of the code, it also works better with the Rails testing and deployment philosophies.”
I agree with Peter, that the example you’ve posted here may be instructive, but it’s certainly not how you need to work with Rails.
And just to be clear: there are no “wizards” per se--thank God--in Rails. There’s a single command ("rails") that builds a directory structure and a code generator that stubs out some two-line boilerplate class definitions. There are third-party code generators that do a great deal more than that, for example a Login generator. But I think it’s important to point out to people who might be concerned about automagic code generation that Rails really doesn’t shove a lot of code down your throat at all.
One of the challenges working with Rails can be the fact that you simply don’t create pages using a single script. Rails uses multiple files that need to be in specific directories to generate pages. This can confuse many Rails newbies....
Peter Cooper writes, "Anyway, I’m ecstatic to have you over on this side of the water."
Warning, Peter: Sam’s just on vacation. He travels the globe. He might not stay on “that side of the water”. Name a language, and he’s fiddled with it, then moved on...
The Universal Packing List Web app to auto-generate a packing list based on trip length and itenerary (tags: leisure trip planning packing list via:lifehacker vacation business) The Usability of Input Filtering More on defensive PHP programming...
Rails Confidence Builder Sam Ruby works with his namesake language and Rails from the bottom up (tags: ruby) Separating Data Model and Serialization not sure I agree, but I found the RDF/OWL approach interesting (tags: xml) mnot on IONA’s...
RSS 2 PDF Free Online RSS, Atom or OPML to PDF Generator (tags: atom rss pdf conversion tools) Sam Ruby: Rails Confidence Builder (tags: programming tutorial rubyonrails ruby rails webdev dev) Sony PlayStation3 - Amazon Product Guide The...
We suspected a pattern was emerging as IBM’s Sam Ruby first at OSCON reenacted the original joke from etech, then posted about the Rails Confidence Builder, and finally combined that work with ATOM using acts_as_tree. Yes, something was in the...
Rails changes the game for developers. That ship has sailed and we’re (almost) all on board. Whether or not the masses believe in our mantra of “10x productivity”, it won’t change the fact that the meme has entered our collective conciousness. I’m...
We suspected a pattern was emerging as IBM’s Sam Ruby first at OSCON reenacted the original joke from etech, then posted about the Rails Confidence Builder, and finally combined that work with ATOM using acts_as_tree. Yes, something was in the...
It’s about That Language. All the software fashion slaves will tell you: down on the plantation, Massa’s new missus is a far-Eastern belle named Ruby. Herewith Ruby remarks: on the Pickaxe, slickness, language learning, and duckstatic typing....
Using Active Record to Test a SQL Server Legacy DB Connection
I recently came across Sam Ruby’s Rails Confidence Builder post and used it as a model to test out my connection to a legacy SQL Server database. I’m undertaking a new project with Mel at Upstate and wanted to verify connectivity before diving into...
RSS 2 PDF Free Online RSS, Atom or OPML to PDF Generator (tags: atom rss pdf conversion tools) Sam Ruby: Rails Confidence Builder (tags: programming tutorial rubyonrails ruby rails webdev dev) Sony PlayStation3 - Amazon Product Guide The PlayStation3......
[more]
jump to the content jump to the menu jump to the contextual information or navigation archives links colophon photolog 2006 01 30 » Google.cn? Did you mean google.com? (1) 2005 12 31 2005 je t’aime When I look back, I think I’ve had a very good...
Just to throw in a heartfelt yes to your leading sentences. I have stumbled into here, and many other places, just looking for a straightforward explanation of how to do an apparently simple thing in Rails. There is no easy way to work with this system until you get to grips with the whole system and it is massive. I am working through tutorials and guides and Ruby coding manuals that all make massive assumptions about my pre-existing knowledge. Everything claims to be easy but it is not. I have had to use every bit of knowledge I have about PHP, Javascript, html to just follow what is going on in Rails. The worst is the time it takes just to find sensible code snippets to explain what is going on. Typically I find wonderful explanations of code to use in a controller and it is simply assumed I will know how to call this from a view, "...simply pass options to this and that and hey presto ...."???? Anyway - thanks for letting me whinge here. Good luck and thanks for the blog.
Sam Ruby: Rails Confidence Builder Welcome! [Ruby-Doc.org: Documenting the Ruby Language] Learning Python, Linux, Java, Ruby and more with Tutorial Videos Conservapedia tries to make Prof. Richard Lenski prove his E. Coli experiment is not a fraud....