RailsConf 2014

Web Applications with Ruby (not Rails)

Web Applications with Ruby (not Rails)

by David Padilla

In this talk at RailsConf 2014, David Padilla, CEO of Crowd Interactive, explores the concept of building web applications using Ruby without relying on popular frameworks such as Rails, Sinatra, or Padrino. The session emphasizes the foundational principles of the MVC (Model-View-Controller) architecture and introduces attendees to creating a web application from scratch using only Rack.

Key Points Discussed:

  • Introduction to MVC: Padilla shares his early experiences with ASP Classic and how it inspired him to implement structured patterns to improve code organization.
  • The Limitations of Frameworks: He discusses how frameworks like Rails can abstract away complexity, leading to a lack of understanding about how web applications work behind the scenes.
  • Using Rack: The session introduces Rack as a minimal interface for developing web applications. Padilla demonstrates basic Rack setup, including how to handle requests and responses with a simple example.
  • Live Coding Session: Padilla performs live coding to build a basic web application, showcasing:
    • The structure of a Rack application with a config.ru file.
    • The implementation of a router and handling different routes.
    • Creation of controllers to manage views and application logic.
    • Separation of views to enhance maintainability using Haml for templating.
  • Dynamic Data Handling: The discussion also covers how to include dynamic data in views, emulate Rails-like functionality without the framework, and manage request parameters.
  • Encouragement to Understand Fundamentals: The speaker encourages developers to explore behind-the-scenes functionality to become better programmers, even suggesting they might want to create their own frameworks one day.

Conclusions & Takeaways:

  • Understanding how to build web applications without frameworks reinforces programming fundamentals.
  • While building applications the traditional way can be complex and slower than using frameworks like Rails, it enhances knowledge and mastery of web technologies.
  • Developers are advised to appreciate the efforts made by framework creators and to continuously seek knowledge in their craft. Padilla humorously concludes by reminding the audience that although using frameworks might seem more straightforward, grasping the underlying principles is critical for long-term growth in software development.
00:00:16.800 All right, let's get started.
00:00:18.720 Hello everyone, my name is David Padilla.
00:00:22.160 You can find me on the internet as Dabit.
00:00:24.800 That's my username on Twitter, on GitHub, and basically everywhere that matters.
00:00:27.279 I work for a company called Crowd Interactive, which is a Ruby on Rails consultancy based in Mexico.
00:00:30.720 We also organize the only conference there that covers topics like Ruby, JavaScript, and more.
00:00:34.719 If you're interested, you can go to the website for more info.
00:00:37.280 Today, I'm here to talk, or more like guide you, through how to write web applications with Ruby.
00:00:41.120 But not with Rails, Sinatra, Padrino, or any other frameworks.
00:00:45.200 First, I want to give you a little background on why I'm here and how this talk came to be. I basically invented MVC using ASP Classic. I don't know if you guys are old enough to remember ASP Classic, but those were the good days.
00:01:01.440 When I was working back then, in my first job, I was doing things like this. I remember being thrown into a project that had a code structure similar to a page called pay1.asp, where all the code was at the beginning. You'd set up your connection and everything relevant, and then in the body of the page, you'd have the dynamic elements.
00:01:10.720 We were running SQL queries and more, but whenever we needed to create another page, we would copy all that code into another file and just change what was relevant. This led to a lot of repetitive code.
00:01:17.760 It was painful to change a layout element, like the page title, because you had to go through each file to make a change. It didn't make sense to me that we had to copy and paste code in this way.
00:01:26.320 So, I came up with a hack. I discovered that there were includes in ASP.
00:01:29.679 I decided to put all my database queries in a single file and then use the query string to drive the application.
00:01:34.720 This allowed me to create a single index.asp file and use query strings to specify different pages. This made things easier, as if I needed to change something in the layout, I would just update index.asp instead of editing every page.
00:01:41.120 Now, before you judge my code, let me remind you that it was the year 2000.
00:01:44.480 At that time, I was listening to a lot of Nickelback. So, you can imagine my mindset back then.
00:01:47.680 I moved on from ASP and went into the world of Java, learning about Spring and Struts. That was when someone introduced me to the concept of MVC, and I thought to myself, 'This is what I needed back then!'
00:01:54.400 After a few years of working in Java, I was fortunate to get a job programming with Rails. I've been doing that for the last seven years and have really enjoyed it. If there's anyone here who has recently transitioned from Java to Rails, I hope you understand where I'm coming from.
00:02:02.240 However, I hit what I would describe as my mid-programmer life crisis. I realized that the days when I had challenging problems to solve were fading. Nowadays, it seems like everything is just there, and all you need to do is bundle in the right styles, and everything gets fixed.
00:02:12.080 This made me feel that programming web applications with Rails was becoming somewhat boring. I felt like I was hitting a mid-programmer life crisis. It seemed like building websites with Rails didn’t require enough programming skill; there was too much magic happening. It felt like calling yourself a great programmer because you work with Rails is akin to saying you're a carpenter just because you bought furniture from IKEA.
00:02:20.640 It begs the question: what is the actual level of skill you’re demonstrating?
00:02:30.400 If you know Constantine, he was ranting the other day about Rails being the worst drag citizen. He mentioned how contributors often don’t add features back into the ecosystem.
00:02:35.840 An example he gave was the lack of implemented encrypted sessions in Rails while it should belong to Rack. The problem is that we as Rails developers tend not to contribute back, possibly because most of us lack an understanding of what really happens outside of Rails.
00:02:42.320 In the past, we would really write SQL and engage with the database directly, but now we don't do any of that. Maybe our minds aren't challenged enough. We need to start thinking about everything outside Rails and essentially bring programming back into the equation.
00:03:02.560 That's why I'm here. I'm going to show you how to write web applications with Ruby, but not using Rails, and perhaps just a bit of Rack.
00:03:11.840 Let me explain what Rack is.
00:03:14.560 It's basically a super cool interface that acts as a bridge between web servers and applications.
00:03:20.080 What happens is that the web server, whether it is Unicorn, Puma, or any other, has a hash of request headers. This hash is sent over to the web application, which, by convention, needs to be any object that responds to the call method and receives that hash. From there, the web application processes the request.
00:03:31.680 The only thing it needs to do is return back an array with three elements: the HTTP response code as an integer, a hash with all the response headers, and the body, which can be any object that can respond to the method 'each'. This array travels back to the web server, which then turns it into something the browser can understand.
00:03:46.880 To run a Rack application, all you need is a file named config.ru. In that file, you'll define, using the run directive, the object that will respond to the call method.
00:03:57.440 Here, you'll see the smallest but most useless web application ever. It's just three lines, yet it works!
00:04:06.720 Now comes the live coding part.
00:04:08.720 Let's begin! I'm going to add the required code into config.ru.
00:04:13.920 In there, we need the run directive, and we’ll create a proc because it can respond to the call method.
00:04:20.000 We will instruct it to print out that incoming hash, respond with a 200 status, and then send back an empty array since it implements the 'each' method.
00:04:27.440 To start any Rack application, all you need to do is run the 'rackup' command wherever there's a config.ru file, and it will boot up.
00:04:35.200 It’s booting on port 9292, and when you go to a browser and reload the application, at that point, there's no output.
00:04:43.200 However, you will see the incoming hash. This output is what the browser sent to the Rack application, capturing all the information the browser provides.
00:04:58.720 Let's actually make something happen with this. We'll create a response structure for our web application, adding a basic HTML body. Even though I'm not very good at HTML, let’s just say it’s 'Hello, World' and see what comes back.
00:05:11.920 We can restart the web server, and voila! We have a functioning web application that serves one page.
00:05:16.560 The current issue, however, is that regardless of what path you call, it always serves the same single page.
00:05:20.160 If you go to the root path or /admin, it’s always 'Hello, World'. We need a router to direct requests to their respective pages.
00:05:33.120 The router takes the request path and sends it to whoever needs to handle that request. This isn't very complicated logic, and we can prototype it relatively easily.
00:05:41.760 We’re not getting into anything complex here; we're just going to implement a simple case structure for routing.
00:05:53.360 We’ll check the path to see if it matches the root path and serve this. If it’s anything else, we will return a 404 not found error.
00:05:58.320 Let’s start up the application and check if our router is functioning. Great! Now we see 'Product Not Found' for any path other than the root.
00:06:05.760 As expected, the server is returning the correct status codes: 404 for not found and 200 for the correct path.
00:06:17.680 Next, we want to organize our code better instead of having everything laid out in a single file. Let’s move this logic into a class.
00:06:24.560 Now that we've defined a class, we’ll make our controller handle incoming requests.
00:06:29.440 This way, our application can grow with more controllers as needed.
00:06:32.560 Let’s create our RootController and define the actions that will respond to incoming requests.
00:06:35.760 Now, as a developer, when we create this structure, we need to ensure that we pass the right parameters and instantiate our variables properly.
00:06:48.960 Coming back to the main application, we’ll make sure to load any necessary files and still allow our web application to function as intended.
00:07:01.920 So let’s check if our RootController functions properly.
00:07:04.400 It looks good! Now, we also need to address views - we need to separate our HTML from our controller.
00:07:13.760 To do this, let's quickly create a views directory and use HAML for our templating.
00:07:19.520 We’ll create a file showing our basic HTML structure. That’ll include a title tag and a body with our H1 element.
00:07:24.480 The controller will then call this view and render it. After building out this functionality, your web application will be organized.
00:07:33.200 So let’s write the render method to allow our controller to present the correct content.
00:07:37.120 What happens is we will render the views using HAML and include appropriate logic to handle our dynamic data.
00:07:50.720 Now, let’s check that everything is rendering correctly.
00:07:55.280 Fantastic! Our views are working, and the title has updated. The whole point of this exercise is to avoid duplicating code.
00:08:04.480 Now, let's add layout support.
00:08:06.960 This will involve creating a layout file that structures the overall design of our application.
00:08:13.760 We’ll set up a folder for layouts and create a layout.haml file for our app.
00:08:20.480 In that file, we’ll define the header and call a yield statement to dynamically insert our content.
00:08:28.560 Returning to our controller, we’ll modify how the render method works.
00:08:31.440 It will now support rendering views inside a layout, providing a structured presentation.
00:08:37.360 Let’s apply these layout changes and verify everything still operates correctly.
00:08:45.120 Alas! We still see the expected output, but now we have a layout file encapsulating our views.
00:08:56.080 The next step is to incorporate dynamic data into our web application.
00:09:02.800 Dynamic data may come from databases or user inputs, allowing our web app to respond accordingly.
00:09:09.920 Let’s see how we can integrate a variable that allows us to change our page output.
00:09:17.600 We will need to define this in the controller to fetch the dynamic context.
00:09:22.640 To do this, we’ll work with params from the incoming request to change our output based on user input.
00:09:30.560 This way, we can improve user interaction with our web application, ensuring it feels dynamic and responsive.
00:09:37.760 Once we’ve set this up to parse incoming data, we can validate it, process it, and display it effectively.
00:09:46.080 Finally, we’ll abstract our web application for maintainability, bundling our functionality into controller classes.
00:09:56.000 Allowing for easy additions of new features or controllers with needed functionalities.
00:10:02.960 As developers, it’s critical to make sure our code stays modular and adheres to best practices.
00:10:08.800 So let’s create our controller class and try to create more functionalities.
00:10:15.440 After moving to a structured approach with controllers, we can verify the effectiveness of our app.
00:10:19.440 Let's ensure that this works once we implement this new structure.
00:10:29.440 Everything's still functioning, which is reassuring. So what else does a web application need?
00:10:38.080 It needs views, right? We need to separate our HTML logic from our backend code.
00:10:47.440 Let’s create our views folder to hold our HAML templates.
00:10:51.120 In this folder, we can store our template files to keep things organized.
00:10:56.799 This will streamline our project structure and prevent potential clutter.
00:11:04.960 While creating our layouts and views, we’ll want to implement a method to render these templates within our controller.
00:11:12.400 That will prevent repeated code and adhere to DRY principles.
00:11:14.960 We'll set methods up to call layout files and render specific view content.
00:11:21.360 It's important to build these templates effectively.
00:11:24.960 Let’s define some basic views using HAML, focusing on text or placeholder messages.
00:11:30.560 This will enhance the visual experience while maintaining function.
00:11:36.560 Now that we’ve got the basic layout and view file implemented, we can run our server and verify everything appears correctly.
00:11:45.440 With that, our web application structure is becoming concrete. This illustrates the development process without any persisting framework.
00:11:51.720 Let’s make sure the views render as expected, ensuring all paths lead to the correct responses.
00:11:59.480 While implementing these views, we are preparing for layout management.
00:12:01.760 Don’t worry, the core principles of web app dev are still clear.
00:12:04.120 Now we make sure our controller can accurately pull the data and pass it out to our views, giving them the required data dynamically.
00:12:12.320 With structure in place and the right approach, we can build scalable Ruby web applications that offer excellent user experiences.
00:12:22.720 In going ahead, we will make sure our controllers, views, and routing are effectively split, ensuring no redundant code.
00:12:31.440 To recap, the last steps we’ll need to take include verifying that requests load the correct data and ensuring the right URL mappings are defined.
00:12:39.040 Depending on the user's actions, the application should reflect changes and data inputs dynamically.
00:12:46.560 Lastly, we would want to extensively document this process and debug any recurring issues.
00:12:53.120 As everything is settling, we can go over building sections where additional feature development is possible.
00:13:02.640 It’s important to remember that improving application logic isn't just about being clever. It’s about using Ruby effectively and understanding what tools empower your end-results.
00:13:12.320 Share your experiences and knowledge along these routes. Ask questions about how the routing works, how to structure controllers correctly.
00:13:21.120 Asking these questions can lead to greater understanding and eventually mastery over building your web applications.
00:13:30.080 Remember to persist with your learning standards and look to enhance your programming practices.
00:13:38.800 The world of web development is vast, but as long as you keep honing your skills, you'll discover unique ways to utilize Ruby effectively.
00:13:46.560 Good luck with all your coding endeavors, and never hesitate to connect with the Ruby community!
00:13:55.600 As you embrace the challenges ahead, remember that understanding is crucial for future-proofing your skills.
00:14:03.760 Lastly, if you have any questions or would like to dive deeper into programming with Ruby, don't hesitate to reach out to the community!
00:14:09.200 We all come together to share knowledge and support each other's growth.
00:14:16.160 Thank you for joining me today, and I hope you found this information useful!
00:14:22.800 Thank you!