-
DAVID PADILLA: All right. Let's get started.
-
Hello everyone. My name is David Padilla.
-
You can find me at dabit. That's my user name
-
on Twitter, on GitHub, and basically
-
everything that matters. Hold on.
-
I work for a company called Crowd Interactive,
which
-
is a Ruby on Rails consultancy based in Mexico.
-
We also organize the only conference down
there that
-
takes topics like Ruby, JavaScript and all
that. You
-
can go to that website if you want more
-
info.
-
And I'm here to talk to you, or more
-
like to, sort of, how to write web applications
-
with Ruby but not with Rails, nor Sinatra
nor
-
Padrino nor any kind of frameworks.
-
First, I want to give you a little bit
-
of background of, of, of why I'm here or
-
where this, where this talk came from. So,
I
-
basically invented MVC on ASP Classic. I don't
know
-
if you guys are old enough to hear about
-
ASP Classic. Those were the good days.
-
So I invented MVC on ASP. Although not really.
-
Not formally. But, when I was working back
then,
-
my first job, it was ASP, and I was
-
doing things like this. I remember, they threw
me
-
into a project that had code like this, that
-
was like a page. They want that ASP. And
-
we had all that code at the beginning where
-
you set up your connection and, and everything
relevant,
-
and then on the, on the body of the,
-
of the, of the page, you have, like, the
-
dynamic stuff and, and, and you ran SQL queries
-
and all that. And then whenever we needed
to
-
do another page like this, we would just copy
-
all the code into page two, dot asp, and
-
just change what's relevant. Right? But everything
was copied
-
and pasted into page and page and page, which
-
was kind of odd.
-
So when I, when I, when I began working
-
with this, I was wondering like, how, how
can
-
this be possible. What happens, like, it was,
it
-
was painful to change something on the layout,
for
-
example. Just the page title, because you
had to
-
go page one, one by one to change whatever
-
needed to be changed, and it made no sense
-
to me.
-
So I came up with some sort of hack.
-
I changed the code to do something like this.
-
I discovered there was some sort of include,
so
-
I said, I, I put all my database stuff
-
in a single file. And then I decided to
-
use the query string to drive to the application
-
and do something like this. So I only had
-
index dot asp, and then through query string
I
-
said page, product list. And then it, with
a,
-
with a fancy case, I will say, OK, if
-
it says products then you have to call products
-
dot asp. If it's another page, call this one
-
and so on. And this made things easier. If
-
I needed to change something on the layout,
you
-
will just switch it in index dot asp and
-
not the whole application.
-
Now, before you judge me for this code, let
-
me remind you that it was the year 2000,
-
right. That is Nickelback back there. I was
listening
-
to a lot of Nickelback back then. So you
-
can think where I, where I was, right. So,
-
it's 2000. I moved on from ASP. I went
-
into the world of Java. I learned about Spring,
-
about Struts. And that was when someone introduced
me
-
to the concept of MVC, and I was like
-
oh. Yeah. This is what I needed back there,
-
but it didn't exist there.
-
And, and if you think about it, it was
-
sort of the same concept, right. Like, separate
your
-
concerns wherever it matters, and, and stop
reusing code,
-
basically. And after a couple of years of
doing
-
Java, I was introduced, then, to Rails. I
was
-
lucky enough to get a job doing Rails programming,
-
and that's what I've been doing for the last
-
seven years. And I've been very happy about
it.
-
So, if there's someone that has recently moved
from
-
Java to Rails understand this feeling. So
I've been
-
happy for the last seven years. Until I hit
-
what I guess I'd call my mid-programmer life
crisis.
-
This, what happened to me is that I was
-
thinking, that was, that was, those days were
cool,
-
where you had all these problems that you
needed
-
to solve with programming and all that stuff.
And
-
right now I think that everything is just
there.
-
You just need to bundle install and the, and
-
the world is solved.
-
So I began thinking, programming web applications
with Rails
-
it's, it's kind of boring. That's, that's,
that's like,
-
I, I, I hit my mid-programmer life crisis,
and
-
it's because I began thinking, like, building
websites with
-
Rails is not enough programming. There's,
there's a lot
-
of magic like, like Akira just said. Just
a
-
lot of magic going on. It's, it's not enough
-
programming for me. It feels like, if you
called
-
yourself a great programmer because you do
Rails, it's
-
the same thing as calling yourself a carpenter
because
-
you bought your carpenter at Ikea, right?
Like. Yeah.
-
I built that, that, that table. Oh, oh you
-
have skills, right? You know what I mean?
-
And, on top of that, on top of that,
-
things like this happened. If you know Konstantin
Haase,
-
he was ranting the other day because Rails
is
-
like the worst Rack citizen there is. And
he
-
was telling, he was telling us that it was
-
because they never contribute features back,
implemented encrypted sessions
-
in Rails, while it should be on the layer
-
of Rack. You know, things like that.
-
And the problem is that, that we, as Rails
-
programmers, don't want to contribute back.
It, it occurred
-
to me that it's maybe because most of us
-
don't know what's going on outside of Rails,
right?
-
Like, if, if you were at that last talk,
-
there's all these concepts that we probably
don't know
-
where, do, that they belong to Railties or
to
-
Rack or whatever. We just think that everything
is
-
Rails, and it's not.
-
And also, well, we used to have all these
-
problems. We used to actually write SQL, you
know,
-
and now we don't do any of that. So
-
maybe, maybe our mind is not challenged enough.
So
-
we need to, we need to start thinking about
-
everything that's outside there. We need to
bring programming
-
back basically, and so that's why I'm here.
I'm
-
gonna try to show you how to write a
-
web application with Ruby, but not Rails.
And maybe
-
just a little bit of Rack.
-
You, I'm gonna explain to you a little bit
-
what Rack is. And it's basically just a super
-
cool interface that acts as, yes, an interface
between
-
web servers and applications. So basically
what happens is
-
that the web server, whether it is Unicorn,
Puma,
-
whatever, has to a hash with requests headers,
right.
-
And that hash is sent over to the web
-
application that, by convention, needs to
be any object
-
that responds to the call method and receive
that
-
hash.
-
And then the web application does its thing,
you
-
know, and the only thing that it needs to
-
do is return back an array with three elements.
-
One should be the http_code of the response,
that's
-
an integer. The, a hash with all the headers
-
of the response, and a body, which will be
-
any object that can respond to the method
each.
-
And that array travels back through the web
server,
-
and then the web server just turns it into
-
something that the browser can understand.
So, like I
-
said, like you've heard, all you need to run
-
a Rack application is the file config dot
ru.
-
And define on that file, using the run directive,
-
the object that will respond to call, and
that
-
will receive that hash of, of headers.
-
So, what you're seeing right here is basically
the
-
smallest but most useless web application
ever. But it's
-
just those three lines and that works. So,
this
-
is the dangerous part. This is where I do
-
some live coding. Call me a rebel if you'd
-
like.
-
So, let's, let's do some live coding. I'm
gonna
-
get out this here. And let's begin with that,
-
you can see that, right? Yeah. That's good.
Let's
-
begin with that config dot ru thing that we
-
mentioned there. We need the run directive
- we'll
-
create a proc, because a proc can respond
to,
-
to call. We'll ask it to print that hash,
-
you know, that we get, that we'll get from
-
the server, and then just answer 200, a hash,
-
and just some empty array, which is an object
-
that responds to each, right. An array can
do
-
that.
-
So, let's see what happens. To start any Rack
-
application, all you need to do is run the
-
rackup command, whatever, to reset that config
dot ru
-
file. And then it just boots up basically.
So
-
it's telling me that it's booting up on port
-
9292. So if you go to a browser and
-
we reload, there's nothing here because we're
not doing
-
anything. But you can see here that we get
-
that hash, right.
-
This is, this is what the browser sent over
-
to the, to the Rack application, and it got,
-
well, all that information that the browser
is sending.
-
So, that is great.
-
Next thing, let's actually do something with
this. So,
-
we're gonna create a body like, like all web
-
application have, and some, well. It will
be body.
-
I'm not very good at html so please forgive
-
me. Let's do Hello World. We'll be, close
the
-
body tag, close the html one. And well. Let's
-
just send that body back. See what happens.
We
-
restart our web server. And boom. We have
a
-
working web application that serves us a single
page,
-
basically.
-
All right. Things are working. The problem
right now
-
with our web application is that it's only
serving
-
one page, no matter what the path is. So
-
if you go, like, to, slash, like the root
-
path, it's Hello World. If you go to slash
-
admin, Hello World. it doesn't matter where
you go.
-
It's always, you know, the same thing. Because
we
-
need something to actually grab the request
path and
-
send it over to whatever it needs to be,
-
wherever it needs to go.
-
So, we're gonna use. That's, that's what's
called a
-
router, usually in the MVC pattern. And the
router
-
just does, does that. It basically just takes
the,
-
the request path, and then send it over to
-
whoever needs to handle that request. Specifically,
this is
-
very complicated logic, in general. It's way
beyond just
-
doing a case structure. But we'll do that
for
-
now.
-
If you want to learn more about the router
-
in Rails, it's a gem called Journey. And as
-
you can see, it has features and problems,
which
-
is basically just designed for Rails and that
it's
-
too complex right now. And you can imagine
why.
-
Like, if you, if you define routes, there's
all
-
these cases that need to be handled. Whatever
you
-
have. If it, the method, and if you have
-
variables and all that, so it's, it's complex
logic,
-
right. So we're not getting into that. We're
just
-
gonna use the same technology that I used
ten
-
years ago, which is define our case, yay.
-
So, first thing we want to do is say
-
something like path equals env. We're gonna
get it
-
from those setters. And then say case path,
and
-
you know, when that path is the root path,
-
just serve this. And if it's something else,
just
-
say hey, not found. And return a 404, the
-
headers and return that body. And that's it.
Yes.
-
That's our router. Sweet.
-
So. We restart our application and see what
happens.
-
So, now product not found. And if you go
-
to root path, Hello World. Great. So, as you
-
can see, the server is getting the same. You
-
know, it's sending the right codes. 404. 200.
And,
-
and so on. So, we now have some sort
-
of router, right.
-
So, what's next? If we, we probably don't
want
-
to have this code, you know, just pasted in,
-
in our whole, in a single file and do
-
our whole web application here. So let's move
this
-
to a class. To, to make it a little
-
bit more understandable. So I'm gonna steal
this, and
-
I'm gonna put it into a app.rb file. OK.
-
Instead of this, I'm gonna say, like, class
App.
-
It has to be, it has to respond to,
-
to call method and receive env, or that hash.
-
And I'm gonna end the method. I'm gonna end
-
that. And ident it. And that's it. Now we
-
have to include that to config dot ru.
-
I'm gonna require that file. And then I'm
gonna
-
tell Rack instead of, of doing stuff here,
just,
-
you know, send the hash to that, to that
-
class, right. Because now it's an object that
can
-
respond to each. Sorry. To call.
-
So this. Let's just make sure that this is
-
working well. I don't want to write a test
-
for this because, you saw the keynote. So,
there
-
you go. It's still working. We have now abstracted
-
our code to, to, to a class. So that's
-
great. What's next? So, I guess what's next
is
-
to go to our, here, and create controllers,
right.
-
Instead of having this laying around. We probably
want
-
a class that says, that does this.
-
So let's create a folder real quick that's
controllers.
-
We'll put them there. And I'll say, let's
say
-
root_controller.rb. What? I know what's gonna.
Hold on. Yeah.
-
root_controller.rb. We say OK. RootController.
And have, I don't
-
know, the action show. This is where code
will
-
be.
-
We probably want to have this controller class
receive
-
that env through the initializer. And then
say, self.env
-
equals env. We added , let's see. And there
-
you go.
-
And here, instead of doing this, we'll just
say
-
RootControll.new, get env and show. We want
to require
-
that controller here. And let's make sure
this works.
-
It doesn't. Perks of live coding. I know what
-
it is. Don't worry. OK. K. So. We start
-
our web application and it's still working,
which is
-
perfect.
-
So what else, what else does a web application
-
need? It needs views, right. We need views.
We
-
need to set our html logic. We need to
-
set it apart and put it in a different
-
component. And, that's like the controller
html pasted into
-
a controller. So let's create views. Hope
you guys
-
like haml. I do. So, we're gonna use that
-
to create our views. First of all, we're gonna,
-
we, we need to create a folder. Views for
-
this controller in specific. All right.
-
So, let's create our views. Show.html.haml.
We need, like,
-
head. Title, Railsconf. We'll create a body.
And h1.
-
Something like that.
-
Controllers, root_controller, and then here.
Let's create a method
-
that will be render. And that method, I want
-
it to receive like the, the, the template
path.
-
And what you need to do to, to render
-
like a template with haml and stuff, you need
-
to open the file first and read it. You
-
need to add some sort of variable, which we
-
call template, and then just say, Dear Haml::Engine,
can
-
you please render this?
-
See, it's easy. That's why I chose haml. So
-
we don't need this anymore, because our superview's
gonna
-
do it, and we're gonna say render('views/root/show.html.haml').
And I
-
think that's it. We probably just need to
require
-
haml. We don't want it to blow up. There
-
you go.
-
And, let's see what happens. Yay. We're still
there.
-
So now we have views. The title changed because
-
on that other version, we didn't have. But
now
-
we do.
-
And, the whole point of what we're doing right
-
now, it's because we didn't want to sort of
-
duplicate code and copy and paste, and so
we
-
probably need layouts, right? Like, like,
like with Rails.
-
So, let's create a layout. First thing we
do,
-
views/layouts. Yeah. That'll work. And let's
open what we
-
have right now. And just steal the first four
-
lines. No, actually, we need everything, all
the way
-
here. Yeah.
-
And we indent it. Let's open views/layouts,
let's call
-
it app.html.haml. Views/layouts/app.html.haml.
And here's where we paste it.
-
And, like good old Rails, we're gonna do a
-
yield, and there's where we want the view
code
-
to show up. I'm on time. That's good.
-
We go back to our RootController, and now
we
-
define a method that will be render_with_layout.
Same thing.
-
We need to know the template path. And let's
-
see, first we open our layout file. We're
gonna
-
hard code it because that's how we do. Layouts.
-
No magic here. Read.
-
And do the same thing. Dear Haml::Engine,
can you
-
please render that layout? The trick here
is that
-
you can pass a block to render, and then
-
whatever you render inside of the block, that's
what
-
gets rendered to yield. So we simply call
render
-
again with that template path that we were
looking
-
for up there.
-
So, now we change this code to render_with_layout.
We
-
restart our application. And it's still working.
So. Now,
-
if I go and change the title, for example,
-
to 2014, then it should, should change. Yay!
So,
-
now we have a layout. That's great. And so,
-
what else do we need from web applications?
-
So, we usually need to have dynamic information
on,
-
on our web application. Something like this.
Like, maybe
-
the name comes from the database, or comes
from
-
a query param or whatever. So we need to
-
be able to change data on the views, right.
-
So, let's see if, first of all, we just
-
add that variable there, like, like Rails,
as if
-
Rails will do it. But we can see that
-
it's not that easy. It, it doesn't happen
magically.
-
So, what we need to do for this to
-
work is we go back to our controller and,
-
well, first of all, we need to define it,
-
right.
-
Let's say, world.
-
And second of all, the render method can receive,
-
as parameter to context of where the layout
is
-
going to be sort of processed. So basically
we
-
just need to tell it the context should be
-
the same object. And, and that way this instance
-
variable will be part of the package. So what
-
we do here is we are going to as-
-
to add the context to our render method. But
-
as default we'll just say hey, just graft
self
-
if there's nothing there. Same here. And we
need
-
to pass that context to this render method.
Over
-
here and over here. So it's all the same.
-
And this is gonna happen sort of magically
because
-
of that default, where we set it to self.
-
And yay. It's working.
-
So now we can populate that variable or, couple
-
of variables with whatever we want basically.
The most
-
typical thing that we could do would be to
-
send it over in a, in, in, in, like
-
params. Like something like this. If it comes
as
-
a parameter, do something, or else just do
world,
-
right. But params is a method that we need
-
to basically define. So let's define that.
Params. I'm
-
not going to write code to like go to
-
a query string. We're just gonna use a method
-
that already exists in Rack::Utils which basically
does that
-
- parse_nested_query. What it's gonna do,
it's gonna take
-
the query string and it's gonna turn it into
-
a nice hash that we can access. So we're
-
gonna add that here in params name and it
-
should work at, at the first attempt. Let's
try
-
it.
-
So, default is Hello, World. It will say name,
-
I don't know, RailsConf, and it works. Hello
Jane
-
or whatever it is, you know. It just works.
-
And, well, I guess the last thing that we
-
could do for a web application will be to
-
properly abstract it. And we probably want
to grab
-
all this code and set it on a controller
-
class, right. Because. Over there. And, OK.
Now, let's
-
go back to our root_controller and just say
hey,
-
just inherit from controller. And that's it.
That way
-
we can, in the end, we can add more,
-
more and more controllers to our super web
application.
-
The only thing we need to do is require
-
controller. Here, and. Let's make sure that
it still
-
works.
-
It still does. That's good. That's always
good. Yup.
-
There you go. So that's it on the coding
-
side. As you can see, you have a working,
-
perfectly working web application right there
from using no
-
frameworks at all, only your Ruby code. Now,
I
-
probably don't have the time to add models
and
-
all that because that's different logic, but.
You could
-
just, you know, inherit ActiveRecord::Base,
they, they, you know,
-
they've already done it. And it's, it's hard
logic
-
you don't need to redo. All you need to
-
do is just, you know, define classes and say,
-
inherit from ActiveRecord::Base, and you will
get, like, all
-
the magic that you get on Rails.
-
If you're a little bit more hardcore, then
you
-
can use sequel, and just write your methods
like
-
so, and you can get access to the database
-
that's, as if it was a hash, and just
-
write your dot all, your dot find, all that
-
logic. And if you're even more hardcore, you
can
-
directly use the pg gem or the mysql gem,
-
and just, you know, do this sort of crazy
-
stuff where you actually write SQL. Yay SQL.
And
-
then just, you know, iterate through the results
and
-
put them in the hash and all that. This
-
is, this is fun. Like, this is programming,
right.
-
And one last piece of advice I have for
-
you is don't ever actually do this. Don't
ever
-
actually do this unless you're some sort of
speed
-
freak or performance freak. When I run my
tests,
-
my super web application was able to handle
700
-
requests per second, and every request will
take one
-
millisecond, which is pretty fast, right.
But when I
-
created the same application using Rails,
I had like
-
2x slowness, right, right. It will take two
milliseconds
-
to, to run, which is unacceptable. I want
one
-
milliseconds. But this is unfair because Rails
solves all
-
these problems, right. We have logging, caching,
database pooling,
-
sessions, cookies, security, all of that,
that we're not
-
considering on our own application.
-
But even if you don't want to do this
-
in real life, you do want to read code,
-
and you do want to go and, and, and
-
try and see how Rails is doing things. You
-
want to try to understand, how is it doing
-
it? Like, right, you want to do find that
-
code that connects to the database, that code
that
-
turns dot find into select star from that
table,
-
you know, all that, you want to go and
-
read and try to understand how things work.
And
-
then once you understand, try to write your
own
-
framework. Well, why not? There's, there's
space for, for
-
a new framework. Maybe, maybe you'll be the
next
-
DHH and will, and will be able to afford
-
and race car and all that.
-
But the most important thing is that you will
-
understand, like, master this topic. You will
know, you,
-
you will have that feeling of saying, hey,
I
-
know how this works. This is great, now I
-
can go back to doing my Ikea software. But
-
I at least I know how it works, right.
-
And then if you see the Rails core team,
-
give them a hug. Because you will understand
also,
-
like, the pain that they had to go through
-
to get Rails to where it is right now,
-
because it's not easy, right. We just, we
just
-
wrote like thirty minutes of code, but it
does
-
basically nothing. It needs to take care of
routing,
-
like I said, caching, security, and all that.
And
-
that's, you know, a lot of lines of code
-
that need to, that need to happen. So, so
-
you see a Rails core guy, you say, hey,
-
thanks for that. Give him a hug. And my
-
last disclaimer is that I do not actually
think
-
that writing web applications with Rails is
boring. That
-
was just added for drama.
-
And I hope you understand that. That's it.
I
-
will Tweet or, whenever you see the slides
you
-
will see like the code example on, on my
-
talk on that, on that url. And thank you.