00:00:10.000
I'm Kevin Triplett, and this is Nick Sutterer from Germany. I'm from Austin, Texas. We're going to be tag-teaming today.
00:00:17.439
This is a Ruby test case, a case study on what to do if you have something written in Ruby and don't like the features it has.
00:00:22.480
The idea is to create a library that makes your life simpler. That's what Nick did, and I found it, fell in love with it, and wanted to share it with you all.
00:00:33.920
This presentation is a testament to the strength of Ruby. Many of you probably work on web applications and recognize MVC, which we absolutely love.
00:00:46.719
Anytime you can organize your code, it's a good practice to do it. This gives us skinny controllers and fat models, but what do we have for views?
00:00:59.640
It seems like we might hate views. I want to change that and share what I found because I'm currently writing a complicated web app.
00:01:13.200
I wanted to use AJAX and Webby 2.0, as they significantly enhance user experience. They offer attractive views, which are not only appealing to users but also beneficial for developers since they help organize views.
00:01:31.240
However, I must mention that components are considered 'dead' starting with Rails 2.0. They killed 'render component' because, according to Rails docs, you shouldn't use components for separating concerns within an application.
00:01:50.560
The idea is that reusable components are not a good way to structure your application. Instead, the Rails philosophy suggests using partials and filters.
00:02:03.439
Whenever I ask why views aren't better, I’m usually told to just use partials and filters. But in my opinion, that’s not sufficient.
00:02:16.160
For instance, Rails provides a solid organization with its MVC structure, having controllers, models, and views. Inside the views, there are different controller directories.
00:02:30.200
For example, take 'users'—it’s nice to have one file per action, and perhaps a partial for handling forms. Or you can be smart and group forms like edit and new into one file.
00:02:41.720
This method keeps things organized, and I love that. But then I run into complications with intricate applications that require scheduling resources, handling users, equipment, and products.
00:03:01.319
I faced an issue when developing an administrative interface with tabs, forms, and many nested forms, leading to chaos.
00:03:16.840
I stated this couldn’t work because I was overwhelmed with partials, despite trying to organize them by naming conventions.
00:03:36.360
This was just one controller in my application, and I found that 'today's tasks' need to appear on every page, which created further complexity.
00:04:11.239
Someone suggested using partials, which I did, but writing a partial statement felt ugly and overly complicated. Passing in nested hashes and the format of rendering was unappealing.
00:04:37.680
Even wrapping partials didn’t fix the core issues. A variable I needed for the task panel was being pulled from the database, so every controller had to initialize that variable.
00:05:03.080
And sure, I could set it up in the application controller with a before filter, but globals pose their own problems.
00:05:22.280
Transitioning back to Nick's experience, he took Ruby and simplified things due to his dislike for Rails' approach to views, creating a library called Cells.
00:05:51.960
Cells are your first step toward widgets, which Nick will dive into later. Notably, Cells work not just with Rails, but also with Sinatra and Padrino.
00:06:03.880
The best part is Cells come with a test suite. Many Rails plugins and gems lack robust test suites, but Cells are actively maintained.
00:06:25.479
Cells provide a dedicated directory where all your widgets can be organized, enhancing clarity. Each cell has both a Ruby file and a folder for its view files for each action.
00:06:50.599
For example, when generating a 'Today's task list' cell, it creates a directory where all your cells reside, keeping things neat.
00:07:02.639
The Ruby file is structured, with supported action methods that allow rendering using standard helpers.
00:07:18.480
Additionally, there's no worry about the double render error common in Rails since you can nest Cells freely.
00:07:39.080
This structure allows for clean code where related views are contained within their corresponding Cells, separated from unrelated content.
00:08:09.960
Cells can also utilize namespacing. If my application becomes complex, I will have nested directories for better organization.
00:08:27.319
Furthermore, Cells allow easy integration with HAML for beautiful HTML generation.
00:09:00.800
Ultimately, I find Cells to be a refreshing addition—organized, elegant, and straightforward.
00:09:13.240
They excel particularly at caching. Although it doesn't implement strict view caching, it does allow specifying the cache directly inside a cell.
00:09:35.279
You can set caching expiration or define its behavior using a block to determine how caches are invalidated.
00:10:18.200
A key advantage of Cells is the ability to test them in isolation. While unit testing is great, view testing can often be integrated poorly.
00:10:40.120
Cells change that by allowing simple tests for each state, making it easy to verify you get the expected HTML output.
00:11:05.360
Moreover, cells lend themselves to inheritance, letting you create variations of a standard widget easily.
00:11:30.280
You can also package these widgets to share them between applications, increasing collaboration within teams.
00:11:52.000
Interestingly, while Rails is powerful, its strength further extends with the introduction of Aoto, which Nick will cover next.
00:12:09.760
Thank you, Nick, for this great talk! Let's give him a round of applause!
00:12:17.960
As for the interactivity aspect, I’ll discuss how to make your Cells act as real widgets that can send data to the server and update in response to events.
00:12:37.480
Aoto is the framework that provides that functionality, building upon the foundation of Cells. It offers interactive widgets, along with statefulness.
00:12:57.760
For those who want even fancier widgets that maintain inner states and structure, Aoto has you covered.
00:13:13.720
We have an interesting event system in Aoto that I developed an affinity for. For instance, I created a small browser game with Aoto, showcasing its capabilities.
00:13:36.680
Additionally, another developer from Canada created a complex backend application using Aoto, demonstrating its versatility.
00:13:52.640
Aoto works excellently for building rich user interfaces, like dashboards that require various lists and forms, employing Web 2.0 features.
00:14:07.640
For today's discussion, we’ll focus on a task cell that Kevin introduced. I've added forms to allow users to input items that sync with the database on the server side and update live on the page.
00:14:30.360
Earlier yesterday, I had a bit too much fun, but today we'll focus on this widget conversion process, step by step.
00:14:50.600
Starting off, we need to generate the widget. There’s a widget generator where I just specify the name of the widget and some standard actions like 'display' using HAML.
00:15:18.640
This will create a widget class and the corresponding standard view for the desired state.
00:15:36.920
The widget then derives from Aoto::Widget instead of just Cells, and creates an action method called 'display', which fetches data from the database.
00:15:53.760
Next, I’ll write a view for this 'display' method, which you’ll find specified in the app/sales/tasks/widget directory.
00:16:15.680
Here, I’ll create a container for my widget that iterates over the tasks to display them in an organized list.
00:16:38.040
To integrate this widget into my controller, I use a class method called has_widgets, which is unique to Rails.
00:16:56.960
This method yields a root widget to which I can attach my 'tasks' widget, accompanied by an ID, which is a requirement for Aoto.
00:17:21.640
It's important to clarify that 'root' serves as the uppermost widget, forming a foundational structure for the rest.
00:17:40.240
To render the tasks widget, I use the render_widget method in the layout of my controller, referencing it by ID.
00:18:03.600
With rendering established, let’s address responsiveness during form submissions.
00:18:27.280
To begin, I’ll add a form to the task list. This includes creating an HTML5 compatible form using unobtrusive JavaScript.
00:18:49.040
I’ll set up a data-event URL that corresponds to Aoto helper methods, which allows for triggering submit events directly.
00:19:09.440
However, please do not execute this code yet since the indentation I’ve used is not correct.
00:19:32.720
Next, it's imperative to add JavaScript to capture form submission through jQuery or any library you choose, keeping the code unobtrusive.
00:19:51.080
Essentially, I will attach a submit event handler to the form and execute an AJAX request to the server.
00:20:09.440
When the form is submitted, it will retrieve the specified data through the data-event URL created by Aoto.
00:20:29.960
Now, let's get back to how my form updates the widget. The event system in Aoto plays a critical role here.
00:20:40.520
By triggering a submit event in Rails, I can capture it in my widget via a method called response_to_event.
00:20:56.360
This method allows me to specify actions that should occur when a particular event, such as 'submit', is received.
00:21:24.480
The processing action I write will handle the form submission, saving new tasks into the database and refreshing the view.
00:21:43.600
In the end, I instruct Aoto to update the widget on the screen with the latest content.
00:22:03.200
This process streamlines user interaction without the clutter of multiple partials and complex Ajax wiring.
00:22:23.040
Next, I devised an autocomplete box widget, demonstrating even further interactivity, triggered by user input.
00:22:39.480
I created a method that listens for typing events and dynamically fetches suggestions in response to user input.
00:23:02.960
Moreover, I explored JSON and JavaScript to create interactive elements, such as drag-and-drop functionality and list updates.
00:23:22.000
For instance, users can drag an item to a trash bin, triggering an event that updates the main list without missing a beat.
00:23:45.200
With Aoto, this is simplified thanks to its event bubbling system, which seamlessly interacts between widgets.
00:24:01.400
In conclusion, Aoto not only facilitates widget creation but also supports further complexity, such as nested widgets and stateful interactions.
00:24:17.560
I’m exploring ideas for a generic widget repository, aiming to enhance the usability of shared widgets across applications.
00:24:33.760
If you’re interested, please check out the online resources and tutorials available at light.auto.de.
00:24:52.920
Additionally, feel free to join me in the sales channel on Freenode IRC for any discussions.
00:25:09.760
Finally, thank you for your attention. Are there any questions?
00:25:25.000
Someone asked whether it's possible to designate specific widgets for replace actions. Yes, you can use the replace method to do this effectively.
00:25:44.320
I also received inquiries about how CSS is incorporated into widgets. Typically, it's taught through conventional methods like importing CSS files.
00:26:06.880
However, we aim to optimize this by allowing CSS to be packaged along with widgets, ensuring a streamlined appearance.
00:26:21.680
Regarding Aoto's widget system, it operates as a foundational structure for lightweight widget design.
00:26:37.840
Ultimately, Aoto simplifies the routing setup for Ajax actions, improving overall efficiency and workflow.
00:26:51.800
Feel free to explore Aoto's capabilities, as it adds a straightforward method for organizing and rendering your views.
00:27:05.520
If you have any final questions or thoughts, now would be the moment.
00:27:26.640
Thank you once again for the wonderful discussions and engaging dialogue!