 Our next speaker is Eric Michaelsover, a non-native San Franciscan. So I guess there's a virtual machine that you run on? That's right. So Eric used to be a code for America. He's done a lot of open source stuff, including Rails admin. And now he's at Neighborland, where he's the principal software engineer. And today he's going to talk to you about all the cool stuff he knows about writing a Rails engine. So thank you, Eric. Thanks, Josh. Hi, everybody. That's good. Not bad for this early. I like that. The coffee's working, Josh. Okay. So this is a talk about writing a Rails engine. And I just want to take a little survey of the audience, get a feel for the room. So who in this room has written a Rails app? Stand up if you've written a Rails app. It's pretty good. I just wanted to get almost everyone out of their seat. So stay standing if you've written a Rails engine. And so I just tricked you. Everyone can sit down now. So I tricked you. And so everyone who stood for the first question should have stayed standing for the second. And the reason, and you can, if you have a computer in front of you, verify this in your terminal. Every Rails application is a Rails engine. The super class of the Rails application class is Rails engine. And so what does that mean? It means every Rails application is a Rails engine. It has some special properties, but really all a Rails application is, is a bootable Rails engine. Right? It's a Rails engine that knows how to kind of start itself up. And engines don't know how to start themselves up, but they're basically everything else that a Rails application is. Right? So you get a full MVC stack. You get, you can have models in a Rails engine. You can have controllers. You can have views. You can have assets in a Rails engine, JavaScript, CSS, images. So it's basically just a little Rails application that you can plug into a Rails engine. And what's interesting is Rails engines can themselves even have Rails engines plugged into them. Right? So you can build engines into engines and then build those into a Rails application, which itself is a Rails engine. So essentially with Rails, it's engines all the way down. Right? There's actually rail ties underneath, but we'll ignore those for now. Rails engines are this fundamental building block of Rails. And so I think that's interesting. And I think it's worth actually taking some time before we get into the technical details to talk about how we got here, how that sort of architecture emerged through the history of Rails. So there's this guy named James Adam, and he's the creator of Rails engines. And maybe engines are something you've heard of recently, like in the last year or two, since they've gotten built into Rails. But engines are actually really old. They predate my involvement of Rails. The first commit to Rails engine, which used to be a plug-in to Rails itself, was on actually Halloween Day seven years ago. And just to give you a little bit of a sense of where Rails was at, this was pre-Rails 1.0. Rails was in version 0.14.2 when the engines plug-in was released. And I don't know about you, this predates engines predates my usage of Rails. My involvement with Rails, I didn't get involved until after 1.0 came out. And I suspect that's true for many of you. So it's this really old concept, this really old feature that Rails has had. And yet it's not widely used and not widely documented as well. So it seems kind of funny to give a talk about this feature that's ostensibly seven years old. We should all be old pros, right? Almost everyone who has used Rails has had engines available to them as a tool. But it's recently gained a lot of popularity and it's been built into Rails. So I want to sort of talk about the process, how that happened in history. So less than two weeks later, right, after Rails engines was released, David Heinemeyer Hansen, creator of Rails, put up a blog post on the official Rails blog. And engines created quite a stir. It was something that DHH felt like he should respond to. And he was decidedly against them. This is a quote and I'll read it. Rails is about making the simple things easy so that you need not abstract them. It's about making the creation of logins, access control, content management, all the business logic components so very easy that you will treasure the application-specific solutions of your own rather than long for the one true login system, right? So he's basically making an argument against much of the way we do Rails development today, right? Bringing in components like omni-auth for authentication or device. Bringing in CMSs, right? So things like radiant or refinery. He didn't think this was the right path for Rails. He basically thought that you should build application-specific solutions that you will treasure. And it will be so easy. Rails will make it so easy to build custom auth that specific to your application, you would never want to use sort of a general auth, one-size-fits-all auth. It should just be so easy to do this. And you can see the title of this blog post from the URLs, why engines and components are not evil but distracting. Because it's basically this distraction from the path which is custom solution should be easy. That's what the goal should be of Rails. It should make it so easy to do a custom thing that you wouldn't even think about reusing a component. And this is further down in the blog post. DHH sort of gets rambly, sums it up at the end. Should engines be stopped? Of course not. I'm saying Rails will continue to send a signal with what's included in the core that this is a sideshow project. It satisfies some needs for some people and that's great. But the goal of Rails is to create a world where they are neither needed nor strongly desired. So I think that's interesting. The goal of Rails is to create a world where engines are neither needed nor strongly desired. That's not the world we have today. I think it's just sort of an interesting historic note. I wasn't using Rails at the time. I wasn't reading the Rails blog at the time. And the path of Rails has sort of diverged into a pretty different direction since then. But the original mission for Rails, the original goal for Rails, or at least in 2005, the goal for Rails was basically not to have pluggable components, just to have Rails. And then if you need something, you should just be able to build it in ten lines of custom code that do exactly what you need. It should be that easy. This is another quote on the Ruby mailing list, or the Rails mailing list rather shortly after that. Engines have not received the blessing of the ROR core team because it would be madness to include them in Rails core. A classic DHH quote, right? No. This is actually James Adams. So this is the creator of Rails Engine saying this on the Ruby on Rails mailing list shortly after he introduced them. It would be madness to introduce them into the core of Rails. Creator of engines at this. So DHH, the creator of Rails, didn't want engines in Rails. And James Adams, the creator of engines, thought it would be madness to have engines built into Rails. So how do we get here? How do we get from here to here? How do we get from madness to engines are, like, a Rails application is an engine. You cannot build a Rails application without building an engine. I think that's sort of interesting. So the next sort of historical point was May 21st, 2008. Ezra Zygmuntowicz wrote a blog post introducing MIRB slices. And this is basically the same idea of engines for MIRB. They were little slices of MVC cake, that's how they were described. So it's basically a vertical slicing of an application, right? You can slice out little bits of functionality and then plug those into another application, use them across multiple applications. And this is sort of how I got involved in the whole story. I was using MIRB at the time. And I wrote this thing called MIRB Admin, which was a MIRB slice. And it was actually, if you look at that link in the bottom, you can see a video of me from the first GoGarucco giving a lightning talk introducing MIRB Admin, which was this basically an automated admin tool, a way to do all the CRUD operations on your database, edit your data in a sort of GUI Web UI for MIRB. And how many people were here actually at that first GoGarucco in 09? Okay, pretty good showing. So, yeah. So anyway, this was not ancient history. And that was actually the first open source project I ever created, was MIRB Admin. And it looked like this. So if anyone uses or has used Django before, it probably looks really familiar. Basically, what I did is I took the open source stylesheets and JavaScript from Django and output the exact same HTML, the Django output, so it had all the same classes and IDs in the DOM. And so I was able to just use their stylesheets and CSS without modifying it. I had a great looking admin with a Ruby backend, a MIRB backend. And I thought this was sort of like a cool example. You see a lot of sharing in the open source community, but not often across language communities. And I thought this was sort of a cool example of a way that different language communities could share front-end code, CSS and JavaScript. So I built this thing and it was cool. And then there was a dreaded day. I remember this day very well. We'll never forget it. December 23rd, 2008. There's some knowing laughter in the room. This was the day that the Rails and MIRB merger was announced. So at this point, MIRB was effectively dead as a standalone project, but many of the concepts of MIRB, many of the ideas from MIRB, including engines, got built into Rails core. And this was very significant. So this is a pretty important moment in the history of how we got from Rails engines being built into Rails and this and now it's 2012 and it actually happened. So as part of the Rails merger, oh, and there was this great talk, which I'd encourage you to all go watch. The video quality is actually poor, but it was a really good talk by Yehuda Katz and Carl Lerche who were core members of the MIRB core team at the time. And they became Rails core members and they did a lot of the work to merge MIRB into Rails. They gave this great talk at RailsConf 2009 called the Russian Doll pattern where basically they described the pattern that I described of being able to embed apps within apps and then embed those apps within apps into other apps. So basically the engines pattern. And that was a seminal talk. Most of what they described was not built, but ended up getting built in the summer of 2010 which was the Ruby summer of code. During this summer, basically the Rails community raised $200,000 and we decided that there should be... that we would get a bunch of interns. I think the history was basically that Google did a summer of code that didn't include any Ruby projects. It was all Python and Java and things like that. And we weren't our own summer of code. So there was sort of this pre-kickstarter campaign to get a bunch of money and organize a summer of code. And one of the projects that came out of that was building engines and sort of taking this... more than building engines specifically, taking this Russian Doll pattern that was described by Carl Lurch and Yehuda Katz and implementing that in Rails. And so the student of the summer of code who did this was Peter Sarnacki and his mentors for this project were Carl, Yehuda, and Jose Valim. So he was incredibly lucky. I think three of probably the best mentors you could possibly hope to have on a project and the project was a great success. Less lucky was Bogdan Gaza. I was his mentor and his project was to port Merbadmin to Rails. And so basically that took the... the Ruby backend, the Merb backend that was generating the HTML that used the Python, Django style sheets and just brought that code over to Rails to work with Rails 3. And so it also got a new look. This is what it looks like today. This isn't actually what it looked like at the time, but I didn't have any old screenshots. This is custom UI. This is something DHH was very particular about. He didn't want it to look like Django. So we made a new skin for it. So yeah, so today it uses Bootstrap thanks to the kind people at Twitter. And so that sort of brings us to Rails 3, right? So Rails 3, it was after the summer of code that this got released, included engines. And there were some... there were people building engines. Rails admin, among many others. Devise, a variety of others. And so this was great, but it was actually a big pain. There was a big pain point, which was assets, right? So if you look back at these screenshots, right, there's all these buttons and icons and selectors and things like that, as well as JavaScript and CSS. And to get these into your main application, you basically had to copy them in. So what a lot of people did is they wrote rig tasks or generators that would basically just do a CP and copy those all in. But one of the nice things that came in Rails 3.1 was the asset pipeline. And so one great thing about the asset pipeline is it would load every engine as it would basically put every engine in the load path for assets. So if you requested an asset, that asset, if it wasn't found in the application, it would then look in all the engines that that asset could be found. And so this was actually a really nice feature in Rails 3.1. And in my mind, this is sort of when engines became like first-class citizens in Rails. And so then came Rails 3.2 and Santiago, who did a bunch of work on Rails 3.2 and is in the audience, I think, all the way from Uruguay today, tweeted this. His tweet basically was that Rails plugins are deprecated in Rails 3.2 and will be removed in Rails 4. So basically the whole way of doing plugins up until Rails 3.2 is now deprecated. The way forward is engines. And so again, it went from being sort of this sideshow to being not only an official built-in way to do it, but basically in Rails 4, it'll be the only way to do it. And so this sort of takes us to the present day. So how do you do it, right? I want to... The title of this talk is Writing a Rails Engine. How do you make a Rails engine? So it's really easy, right? It's basically just like writing a Rails app. So when you write a Rails app, you say Rails new and give it a name. To create a Rails engine, you say Rails plug-in new and give it a name. And if you want it to be a full-mountable engine, you have to pass the flags full and mountable. And those basically... Mountable basically means it's not a standalone engine, but it's the type of engine that you'll be embedding in another app. And full means it's basically not a plug-in, like an old-style Rails plug-in, but that it's actually an engine. So full means like engine, basically. And so if you type that command, this is what it looks like. Again, very similar to what you get if you type Rails new. Obviously it's a subset of that, but pretty similar, right? So there's an app directory. It has a controllers directory. It has models and views and assets and helpers directory within it. This should all look very familiar. And there's a lib directory as well. So I'm just going to take you through some of these files and some of the sort of important ones that you'll need. So lib and then your engine name dot rb. What this does, the first thing it does is it just requires the engine, right? So that's in a directory with your engine name and that's engine dot rb. And then it defines a module, which is the name of your engine. So this is basically a namespace for your engine. So if you have any custom code, any custom methods, things that are specific to your engine, not necessarily MVC stuff, but just library code, you can define this in here. And then, so this requires my engine engine. So if we look at that file, again, this is what it looks like from the generator. So the fact that you said mountable that basically gives your, it carves out a whole namespace for your engine. And if you have any initializers or things like that within your engine, then you can define those in here, right? So all your initializers go in here and you can see my engine engine inherits from Rails engine. And that's the magic line that will add the engine to your load path, right? So if you don't have that sort of second line down, then you won't sort of get all the benefits of it being an engine, but just by doing that, you inherit all the properties of an engine. One difference between building an engine and building a gem is most of you when you're adding dependencies to your application, you put those in your gem file. With an engine, you don't want to do that because what you're going to do is you're going to package up this engine and you're going to distribute it to other people. And the way you're going to do that probably is as a Ruby gem. It's a default gem file when you create a new engine and you basically don't want to touch it. Basically it specifies Ruby gems as the gem source and then it says that gem spec method basically says go get my dependencies from the gem spec, right? So that's where you define your gem and then Bundler will know how to pull those dependencies from your gem spec. So you might think if you want to add a dependency, you'd add it to your gem file, you actually add it to your engine name.gem spec. One difference. There's also a rake file and you can write custom rake tasks for your engine. They will be scoped with your engine name and you just put them in lib tasks. So again, just like writing a Rails app, but it's an engine. Everything looks the same so it should feel very familiar. Again, just like writing a Rails app, you can define generators in your engine. And again, they'll be scoped by your engine name. So you can just put those in lib generators and off you go, right? It's just like writing generators for an application except they're namespace within your engine. And again, there's migrations as well. So just put them in the right place and you're off to the races. There's one really nice rake task that will automatically be defined for you when you create an engine, which is myengine install migrations. And what that will do is it will install your migrations and it will copy your migrations into the application, but it will only do the ones that it hasn't copied in previously. So if you release one version of your app and that has some migrations, people can run this rake task and then if they upgrade to a new version which has new migrations, they can run this rake task and it will only copy in the new migrations, which they can run as they please. So this is really nice. This is something you get for free again Routes. So this is in your myengine config routes. So again, config routes is the normal place where you put your routes, but instead of it being Rails application routes draw, it's myengine colon colon engine routes draw. And basically you're defining scope routes that apply just to your engine. But other than that, the routes look exactly the same. So the generator creates this sort of scaffolding for you and then you can just put in your normal routes. And then in a user's application, when they mount those routes, they just say mount the name of your engine at and then some path. And so, for example, Rails admin, a lot of people like to mount that at admin, but if they already have that route for something else, like maybe they've built an internal admin tool or they're using active admin or some other admin engine, you can actually run two engines that sort of cover the same responsibility and define a custom route really easily. So this is basically the code that you give to users of your engine on how to install it other than putting it in your gem file and then you mount it. Testing engines is actually a little tricky and the sort of best practice there is that what you're going to do is create sort of a dummy application that lives inside your test directory, mount your engine into that dummy application, and then test that dummy application. And you can create multiple dummy applications if you want different configuration and things like that. But it's a little bit hacky, like to have a whole Rails engine, a Rails application in your test directory, but that's sort of the best way to do it and it works. And a lot of the information from this presentation and if you want to sort of, it's only a 30 minute talk, but if you, and I'm at the 28th minute, so if you want to dive in and really get a good sense of how this stuff works and more specifics, I really encourage you to go to this Rails guide. This is the URL written and compiled mostly by Ryan Big, but also others. It's a really good guide. These Rails guides are a great way to get started on engines. And so this is kind of the last question, which is I get a lot when I've given this talk in the past and it's basically when should I write an engine, right? And my answer to that is if you're ever at a point where you have two different Rails applications and you want to share a piece of code, a bit of functionality across those, that's a great use case for an engine, right? You can basically slice out that functionality into an engine and then require that as a gem in both of those applications. So that's one main use case, just the reuse. And then the other use case is just if you want to isolate pieces, right? So maybe you don't want to share it, but maybe you want to have sort of like a base or there's like some almost like scaffolding or some base things that you want to use to build every other application. That's like another use where you can just create, instead of creating a Rails app and then like forking it and kind of building on top of that, you can actually just do it as an engine and then you'll have like all, let's say you want to have certain assets that are always there when you start an application, like a template for building a Rails application. A really good way to do that is basically by using an engine. And so yeah, that's what I've got. Thanks for listening. And I think I have about a minute for questions. And if you have other questions, you can find me on the internet. I'm SF Eric at just about every internet service. Thanks.