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.