00:00:20.240
I'll be talking today about Rails 3.1.
00:00:26.080
My name is Ben Scheirman. I spoke here at LoneStar last year, and on the Thursday when I came into town, I started to get sick. Last year, I had just the raspiest voice and I couldn't participate in the bar conversations. By the time my talk came up, I could barely speak at all. So when I came down this time, I started to feel that scratchy throat again. Luckily, it's not as bad as last year, but this seems to be a tradition that Ben is going to feel sick around this time. So, I apologize for that.
00:00:38.160
A little bit about me: I'm the Director of Development for Chai One in Houston, Texas. We do iOS and Rails development, and we're looking for some people, so if you work with iOS, Rails, or Android, let me know. I also enjoy drinking beer and playing guitar, so I think I'm in good company here. You can find me on Twitter at 'subdigital' and on my blog at flux88.com.
00:01:21.759
All right, let's talk about Rails 3.1. If we take a look at what Rails 3 did, it brought a lot of componentization and the merging of the Merb project, making everything pluggable. Rails 3.1 is what I like to call the 'return of opinions' release. There are some pretty strong opinions in Rails 3.1, so for a dot release, it's actually quite significant.
00:01:52.399
I'm going to go over what's new, and then we're going to drill into each one of these sections. First, and probably the least controversial change, is that jQuery is now the default. We also have reversible migrations, mountable engines, the Identity Map, prepared statements, has_secure_password, HTTP streaming, the asset pipeline, CoffeeScript, and SASS.
00:02:10.479
The jQuery integration is fairly innocuous. You simply add a new line in your gem file for jQuery Rails. And if you are one of the few holdouts for Prototype, you can still uncomment that gem and add Prototype-Rails to your gem file, and everything will work just fine.
00:02:40.560
Another new feature is reversible migrations. This concept is fairly straightforward. Previously, our migrations had an 'up' method and a 'down' method. If you created a table in the 'up' method, you'd have to drop the table in the 'down' method. Now we just have a 'change' method, which simplifies the code. If you create a table, it will automatically handle the dropping of the table for you when rolling back.
00:03:16.640
Additionally, we have mountable engines. An engine is like a Rails plug-in that contains everything, including controllers, models, views, routes, initializers, and assets. It's like another Rails application that you can embed inside of your Rails application. For example, if you have an engine, you can embed it inside different applications. The important part is that it contains assets, as well as views, so you can include your own JavaScript, CSS, images, and more within those other Rails apps.
00:03:47.359
Creating an engine is quite easy. You can do this by running the command 'rails plugin new your_engine_name --mountable', and it generates an app that looks like any standard Rails application, along with a gemspec that includes an engine class. To embed it in a containing application, you would open up 'routes.rb', and specify 'mount your_engine_name: :engine', which denotes the path in your application used to access that engine. Essentially, it's just a Rack application that Rails passes requests to, allowing it to process its own routes.
00:04:20.239
Next up is the Identity Map, which is common in other ORMs. If you've ever used Hibernate, NHibernate, or similar frameworks, they all have an Identity Map, and ActiveRecord now includes one as well. When you call 'customer.find', it executes a statement against the database, placing an object in memory. If you run the exact same statement again, it caches the result, but we end up with another separate object in memory.
00:04:45.520
What the Identity Map does is return the same object in memory consistently, meaning you're always dealing with the same memory location. This can help reduce memory usage in long-running processes or when using multiple methods in controllers. However, it should be used with caution, as it can break some complex relationships in certain scenarios. Therefore, it is off by default. If you want to activate it, you can do this in 'application.rb' with 'config.enable_identity_map = true'. Alternatively, you can use it within a specific case using 'ActiveRecord::IdentityMap.use' within a block.
00:05:29.840
Next, we have prepared statements. Does anyone here use SQL Server? A couple of people? Great. So let's say we have a query like 'SELECT * FROM customers WHERE id = 128'. If we execute the same query with a different parameter, it can generate different execution plans on SQL Server due to how it is configured. Prepared statements take that query and cache it, sending a token along with the parameters, resulting in less text being sent to the database and enabling reuse of the execution plan.
00:06:01.440
This leads to substantial performance improvements on SQL Server. I heard a statistic on the internet about a 10x performance increase, but I couldn't verify that. However, it's a significant win for SQL Server. We also saw small gains for SQLite and PostgreSQL, but unfortunately, MySQL performance degraded when using prepared statements. It seems that MySQL already implemented a similar optimization, and adding the extra call to prepare the statements led to redundant calls, which is why it's disabled for MySQL adapter.
00:07:57.360
Moving on to 'has_secure_password,' what is your favorite authentication system? If you're starting a new project, which one will you use? I've had issues with many of these authentication systems at some point. There seems to be a lot of magic involved, and just when you understand how it works, an upgrade to Rails 3 breaks everything. Ryan Bates from RailsCasts suggested that it's pretty easy to roll your own authentication system, and I agree, especially now that we have 'has_secure_password' in ActiveModel.
00:08:43.680
To use 'has_secure_password', you would have a users table and add a password digest column. In your user model, you simply say 'has_secure_password', and this gives you virtual accessors for 'password' and 'password_confirmation'. When you call save on the user, it uses bcrypt to encrypt the password and store it in the password digest column. You can then authenticate the user by calling the 'authenticate' method and passing in the password. If the password is incorrect, it returns false; if it's correct, it returns the user itself.
00:09:35.519
Next, let's discuss HTTP streaming. Nearly every major web framework, except Rails, does some form of HTTP streaming, primarily for performance. Without HTTP streaming, the client makes a call to the server, which conducts a render step to render a template and sends it back to the client. At this stage, the client notices it needs to fetch some assets, fetches them, and finally renders the page. This process can lead to delays.
00:10:00.560
In contrast, with HTTP streaming, when the client calls 'get items', the server continues to render. As soon as a particular section finishes, it can send that part immediately. The client notices that some assets need to be grabbed and can start fetching them while the server completes the render process, sending the final HTML as it finishes. This reduces the overall wait time for the client, as assets can be requested and loaded earlier.
00:10:47.360
Now, let's take a look at my Rails version. I will check if everyone can read this. Do I need to make it bigger? All right. So, Rails 3.1 is currently on RC5. I expect it to be released very soon. Next, I'm going to run the command to create a new Rails application called 'streamer' and wait for it to complete the dreaded bundle install on the conference network.
00:11:50.800
As I wait, I might need some elevator music during this step. All right. Now we have a Rails 3 application set up. I plan to open it up and examine the gem file, as you cannot use HTTP streaming with the built-in WEBrick web server. Therefore, we can use Unicorn instead. I'm going to add some configuration for Unicorn in 'config/unicorn.development.rb'.
00:12:13.920
Next, I need to ensure that my bundle is installed. Once installed, I will use the Unicorn command with the configuration file, and then we can start our web server. After this, we'll check to ensure it's operating correctly. Everything seems to be working, so now I'm going to create a basic controller and action.
00:12:41.040
Inside this controller, I will render some text initially. To demonstrate, I will simulate some complex rendering using 'sleep' within the view. When I visit 'demo streaming', I notice there is a significant delay before it comes back. This delay is much more evident when using cURL to check the time taken.
00:13:19.680
To improve this, I can just add 'stream' at the top of the controller. When I execute the cURL command again, I can see that the head tag is returned immediately, allowing me to fetch the CSS, JavaScript, and then eventually receive the body content. Additionally, if I run 'cURL -i' to inspect the headers, I notice that the transfer encoding is chunked, which is a new feature of Rails.
00:14:05.680
This method is generally beneficial as it allows the client to begin fetching assets sooner. You can also perform actions like rendering the streaming using the statement 'render action: ... , stream: true' to apply the streaming behavior selectively to one action.
00:15:00.560
Overall, the objective with HTTP streaming is to flush the head tag to the client as soon as possible, allowing them to start fetching assets. However, there are a few complications, especially when using yields with named blocks for content provision like sidebars. The way Rails templates work means that content for named yields can be accumulated and rendered only after the entire template is finished. Thus, the yield tag must wait for the complete rendering process before flushing content to the client, which can negate the benefits of streaming.
00:15:55.160
An example accomplishes periodic flushing to the client by introducing a new method, 'provide'. So, if we yield a title, templates can set the title for individual pages with the 'provide' method, indicating that once done, that section is ready to be sent to the client.
00:16:41.040
This approach must account for the limitations of Rack middleware, which may break under these streaming conditions. If any middleware inspects response behavior, it might try to log timings that become unreliable, returning responses prematurely without the render being completed. Additionally, middleware that injects content may not function properly due to Rack's current design not accommodating for streaming well. It indicates that while streaming support exists, further refinements are needed.
00:18:00.000
Next, let's discuss the Asset Pipeline. A typical application consists of numerous JavaScript, CSS, and image files. When working on a project I previously developed, I found that all the JavaScript code was consolidated into a single file. The motivation behind this organization is to reduce HTTP requests, as it's recommended to minimize the number of requests made when loading a page. Another advantage of bundling is minification, leading to smaller sizes for assets. This is where Sprockets comes into play and is now included as a dependency in Rails 3.1.
00:19:09.280
Sprockets compiles all these assets, concatenating them together in a logical order and minifying the result. Consequently, the resulting file becomes what you include in your HTML page to provide all the styles and scripts. To illustrate this, we will add an action to our controller to demonstrate how the asset pipeline operates.
00:19:58.160
In this example, I’ll create two different divs styled differently. Once I visit the new pipeline action, I want to ensure that everything is functional. Looking further into the application directory, I can see that a new folder called 'assets' has been created, which houses images, JavaScript, and stylesheets. I’ll explore the existing styles and make some modifications to enhance each div’s design. Even though I am defining custom styles, Sprockets will combine these styles and supply them as a single CSS file.
00:21:16.160
When inspecting the source of this new page, the previously mentioned demo.css file is not being included, as Sprockets has intelligently aggregated it for me. This produces one request for CSS and another for JavaScript, simplifying the process. If I create additional JavaScript files within the assets folder, Sprockets takes it upon itself to bundle everything efficiently, which facilitates smoother management of my asset files.
00:21:56.480
There is another note regarding Sprockets that it depends on a server-side JavaScript environment. For Heroku deployments, this may create issues, necessitating the inclusion of the 'ruby-racer' gem. The gem version 0.8.1.3 is the latest that works with Rails 3.1.
00:22:44.160
Now, let’s shift gears to CoffeeScript. Recently, a simple commit on GitHub regarding CoffeeScript has led to an overwhelmingly long comment thread, showcasing the community's strong opinions on its inclusion in Rails. Some developers have expressed concerns or confusion, asking if they must use CoffeeScript in their projects. To clarify, you do not have to use CoffeeScript if it is not your preference. However, it is included by default now. CoffeeScript serves as a streamlined language that compiles into JavaScript, eliminating much of the superfluous punctuation you typically encounter.
00:23:44.800
The syntax of CoffeeScript lacks certain keywords like 'var' and 'function', resulting in a cleaner codebase while retaining functionality. It’s whitespace-sensitive, forming an elegant structure, meaning less clutter overall. The conversion from traditional JavaScript creates a more natural coding experience for those who are familiar with Ruby, while still respecting JavaScript's underlying mechanics.
00:24:37.760
Next up, we have SASS. You may have noticed that I previously entered CSS into a file saved as SCSS, which is a syntax compatible with CSS. In contrast, SASS introduces variables and mixins, allowing enhanced organization and management of stylesheets. For example, I might need various colors associated with certain components in my website. By creating a variable for each specific color, I can ensure consistency and easily modify values when required.
00:25:19.040
Once I define these variables, I can easily write expressive syntax that nestles components together, efficiently reducing redundancy in my code. Instead of duplicating CSS rules across various selectors, I can encapsulate the declarations within a single mixin, easing future adjustments.
00:26:07.560
In closing, SASS allows for nuanced control over styles via variables and nested rules. Yet, using variable scopes carefully becomes paramount in ensuring clarity when referencing variables across diverse style definitions. Furthermore, I find the SCSS syntax to be less confusing compared to the original SASS syntax. It remains imperative to familiarize yourself with how Sprockets orders and handles these assets and compile them correctly within Rails applications.
00:27:44.160
Are there any questions? Yes, that's a great question. If you're working with multiple files that utilize variables, you need to ensure proper loading order. By adding 'require' statements, you can explicitly register specific files to load before others to maintain variable accessibility.
00:29:27.760
Furthermore, while Rails 3 did support engines, this release enables wider integration with the Asset Pipeline. Moving forward, I hope to see improved developer experiences as we explore the enhancements offered by Rails 3.1. Thank you all for your attention today. I'm excited to see how you leverage these new features in your projects!
00:30:51.199
Thank you very much!