 Being in this country now this this country America for two weeks now But before that I spent some time in New Zealand and what happened there was we had an event called rails camp Which was like a base of a mountain to climb from the top of the mountain and then this guy is a glider off in the distance circling doing its thing and then it turns and starts heading towards us And we're like okay. This is kind of cool, but then he's heading towards the bridge line Like shit shit shit, but that's the rich line. He's heading towards and then This is a steal from the video he's no more than 20 feet above our head So I was camp in New Zealand was amazing if you ever get the chance to go to a rails camp event in Australia on New Zealand They're pretty spectacular My cat is a thing about West the start so I might think about rails camp Now my name already I'm Ryan big you've got me on Twitter at Ryan big and I'm also known as radar You can see me on GitHub as radar. I see his radar and you can also call me right out. I know what you offended Some people give me some kind of a hero, but it's actually just a costume. I put on I have that a lot on I see and stack up a flow and I don't means a lot if you see me posting an image link to something It's probably one of things Called Real Street action if you haven't read it yet. You're a very bad person As I said before I have a stack out low. I have 27,000 my hundred and twenty six reputation points I'm in the top six top point six five percent, which means that I'm definitely part of the 1% I work for a little company may have heard of called spree What I do this right is I'm the community manager This means that I spend most of my days on this page. I just stared it Boping that all the issues will just go away On the rails country is list. I'm surrounded by people like Michael Cosiasky who basically commits to rails every single time you go to a run Be a sonaki who did a lot of the work on engines and talking more about him later Nicholas second. He's an interesting character. He disappeared in 2007 basically often like he commits to give up every now and again But he hasn't committed to rails since 2007. I don't have a story behind that and this is my old boss I'm out wrecking my old boss. Just pretty awesome Anyway, no one not talking about that talking about engines today So engines was great for the idea of engines and rails came up into the mind of a guy called James Adams James Adams Wanted to make mountable applications inside a rails application So on October 31st of 2005 when rails was still in its basic infant infancy 1-4.2 He decided he'd make this mantle manable engines plug-in And so he got together with some friends and rated And some people didn't like it this guy called Kevin Smith He he had some nasty words to say he said the engines are a nasty hack that breaks every new version of rails And this is actually true because every time rails changed the engines plug-in would need to be changed And that caused problems In this same blog post that Kevin wrote he said that stopped trying to write need to age extra and then he said the blog post wasn't The blog post wasn't entirely spot on he basically is his advocating you shouldn't be using backbone or MRL power or any one of the other than what is it now 6.5 million JS frameworks And THH even didn't like the idea of engines He said he He said I didn't want rails to succumb to the law of high-level components like login systems forums content management and the lights He didn't want device didn't want forum. He didn't want refinery, and he didn't want spree He didn't actually say those things, but basically by that statement you can refer those things So he says that but the goal of rails is to create a world where engines are neither needed or strongly desired Obviously, we're not quite there yet. He said this at the end of 2005 and now it's the beginning of 2012 and hey engines engines are now just here And James Adams even played devil's advocate. This is the guy who created the engines plug-in who is like This was his livelihood. He said the engines have not yet received the blessing of the Ruby on rails core team And I wouldn't expect any different because it would be madness to include them in core rails He used the word madness that means like extreme insanity But yet rails had engine support and I had it through this engines plug-in and Then rails 2.3 came along and kind of mocking me implemented engines It worked to the degree you were able to have controllers models and views But to copy other migrations and the assets that was generally a pain in the ass The browns castling at the bottom is a demonstration of how engines worked in rails 2.3. It's pretty awesome You heard cats came along after that and he brought all the good ideas from her some of the bad ones But when rails He saw the engines work and some people are kind of holding and said look We would really appreciate it if we could have engines become like a first-class citizen within rails And if you've seen any of you who distorts of I guess the La Paz tiki is some of them He's mentioned engines being like this massive third thing So for Ruby on Ruby summer of code Peter Sarnaki this guy in Poland came along and he said I think I think I can do So he did he actually committed 322 times to rails Engine work. That's the commits. I found Yeah, he's done a lot of design craft on a boat. He's actually above me on that list So engines are bought in rails 3 wasn't so bad after after all of your hooters and Peters and I think Rain Hendricks, New Zealand Today he was involved in college So it wasn't so bad and then rails 3.1 came along and it's like, oh, yeah Awesome. There's no you who I would copy of the migrations and you have the asset pipeline and does all these awesome things Really useful So for spree We were using engines I use the engines I use the spree Jammed to build a site for the ABC in Australia. They're a massive broadcasting corporation They're a government funded broadcasting corporation that have products. They want to sell them So they brought us my team in to help out this thing So before spree will one that oh with engines. I really absolutely had no idea what I was doing So What happened is that spree would have a model called product It would just be at the top level in their space would be cool products and you get all the products you do product model The problem with this though is that if you want to have the application having a product model it would break Because well spree would break the application would be fine It's free with break because the application is going to recognize the product model and go hey It's in my app models product cool found it don't need to go looking for any other product model because this is So that was interesting and it was during this time that I was actually writing the engines chapter for a Austrian action like Many others and coming across all these difficult problems with engines So I turned to the documentation of rails, which is known to be like All and just it explains a lot of things In very few words So the rails engine class right now has only in 300 lines of documentation And so you're reading it and you're trying to understand exactly what her rails engines do That doesn't explain it. So then you just go back experimenting So this is how you get started with an engine to run the rails plug-in you command and you generate a new plug-in And you pass the full option to that what that does is it adds the routes file So you have a config routes you have engine routes it adds an app folder it adds an engine class and couple of other things Assets as assets then you have manageable the option of mountable and that Inside a plug-in when you generate a new plug-in in rails It has a test dummy application and all that manageable option does is mount the engine inside the test dummy application which is inside the engine if that makes sense and And the great thing about this is that all the plug-ins for rails are now a gem by default So this means that you can put it on github and inside your application you can point it It's a gem log and point it at the github repository You don't really have to do anything to settle that up So you don't have to use don't use tools like dual or a bundler to get it set up and running Because of this you don't need to put the dependencies in the gem file if you do put the dependencies in the gem file Again, you're a very bad person You should be putting them instead inside the gem spec the gem spec You have yeah, you add development dependencies So like aspect and capi bar and so on and you can add normal dependencies like rails or how more if you want So inside an engine you have a file called the engine name which just requires the Blog engine and defines a module inside this module. You can put all kinds of setup Inside the engine file it inherits from a classical Rouse engine what this is is That it's the kind of the basis the engine so it adds all the app It adds a path to the auto. Sorry at the app directory to the auto low path You should work around And it does around since on so far it also allows you to define initializers inside your engine So you can have an initializer running before your before your engine boots You can also tell to use the web Scout Rm which I hear is good upcoming What you don't understand though about Brown's engine Maybe some of you do is that rails application actually inherits from rails engine Which is kind of awesome because when you read the rails application documentation It says that in rails 3.0 a rails application Object was introduced which is nothing more than an engine but with responsibility of coordinating the whole room process So every single rails 3 application you're writing right now is actually an engine Just kind of amazing So inside the blog engine class you can also set up an endpoint To the points or rack application So instead of having your routes inside your engine you can have a rack application serving the requests This means that if you want to create a rack application and still have the power of rails like having the generators and the initializers You can still do this. You just build a rails engine and it works Inside an engine you also have a file which I'm sure all of you are familiar with don't really need to cover that I just thought I'd put it in there Config initializers and locales and routes Same thing as an application. You don't really There's no difference You can also write generators inside an engine So if you have device has this generator that you copy out of the views It also has one for the user model and so on so forth There's some great tasks that come a stand this one called install migrations We'll actually copy over all the migrations from the engine the first time you install it And then if you update the engine later on and copy over the migrations again like run the same command You'll only copy over the migrations that haven't yet already been copied over Unfortunately with a rails engine there's not a good agreement included. So please well, I've got Otherwise you're a bad person So with the engine work that I was trying to do is trying to build the best rail street at one forum system cool forum I try to build the best rail street at one forum system ever And this was really easily accomplished because it's the only rail street at one forum system ever So with this With rails 3.1 came namespace. So in an application This basics again, but when you run rails to you model post it generates a model at app models post makes sense Inside the engine previously in rails 3.0 and before You would run rails to you model post and it would generate a model inside the engine at models post So in your application you reference post at the top level and it goes to the engines post But if you have a model inside your application cool post who has a model cool post in your application Yeah So if you have a model inside your application called post it's going to go to that one first and not see the engine one So how do you make it see the engine one? Well, you could just call it something different Right, you just call it forum post to the whole PHP namespacing thing Where you just put the name of your company before all your classes We can leave that to the PHP developers, I think So in rails 3.1 you have this thing called isolate namespace which really like one line in the engine class and does so much First thing it is. Yeah, there's a new user When you generate when you generate a model cool post It actually namespaces it so instead of generating an app models post it now generates an app models forum post That also namespaces the class This means that inside the application you reference it as forum double column post and you can still reference your applications model post So that removes the whole conflict thing there You've got your model now namespaced for your engine and you can still access your applications models It also namespaces the tables So if you have a post stable in your application it won't conflict And if you have a post controller it won't conflict because it's namespace and you have post views it won't conflict because it's namespace So you get the idea Previously in rails Engines you would have to draw the routes onto the application itself. So instead of being this mountable application kind of like Is it kind of a parasitic attachment? So previously you would need to do this you would draw the application routes like this You would namespace it with a name or maybe namespace it Under the name of your engine and then draw the routes inside that now. That's just that's just terrible. You shouldn't You shouldn't have to do that So instead of what comes along in rounds 3.1 is that you draw the routes directly on the engine class itself This means that instead of having to draw them on the application and then have a namespace you just Draw the routes on the on the engine and then they're already namespaced Inside your application you just mount the engine at a specific path And that way then when you access that path it'll go to the engines routes rather than the applications There's a couple of caveats with this First one is that inside the engine you can reference You can reference a method called forums path and that's going to go to the correct path for your engine But if you reference that inside the application You're going to get an undefined method because it's going to be looking at forums path on the applications routes May find it may not find it depends on if you have a forums resource If you don't have a forums resource undefined method So again around this what you need to do is you need to prefix it with the name of the engine So in this case the engine is called forums so we call forum dot forums path and that will always give you the route to the forum Inside the application you can have drop bears path. Who knows what drop bears are? Yeah, cool Those the uninitiated um, you know koalas are in australia the little cute cuddly creatures sharp claws don't don't And teeth and teeth They eat leaves on trees, but they Sharp claws and teeth. Anyway, drop bears are the same size as america's grizzly bears. They're gray They sit at the top of gum trees And when something big enough walks underneath them they fall and they drop And they crush them crush them eat and then climb up the tree and sleep And when they're hungry again, they fall off and yeah, anyway So the only way to repel drop bears is that you put bergiumite in the back of your neck Just like a stupid out of the top back of the neck. They hate the smell of it So back of the neck to the best spot because they can see it and they hate it So yeah, if you're talking drop bears inside your application, you have drop bears path like this If you reference drop bears path Inside your engine or if you have part of your application that's rendered from your engine I know it's crazy happens That would raise an undefined method and so To get around that you use main app. I don't like the name of this So I prefer to be at but there's apparently a lot of bike shedding that went on this because what the app is there There's the application and the engines But you just call main app and it'll always go to the applications routes These methods like forum and application you can also use to You can also use it in your form for us. So if you want to do if you want to create a form that goes to The engines routes you have form for the name of the engine and then the resources actually normally won't There's a couple of other hard problems that I sat around thinking about Um, the first of which was how do we do authentication inside the engine because there's Looks like different different opinions on how to do authentication. So people will be used off-watching hands up Clearance Shout if you're using clearance Embarrassed youth Sorcery Device Restwall Custom solution Right. So how do you make how do you make all these people happy? It's free. We I think we're doing it wrong. We have a core engine called spray off Which provides a device authentication solution And so if you want to use anything else that's not device, you're going to have a very hard time integrating with that So my view of authentication is that it's just not my area of concern If you work and help us you'd have this like come to me afterwards. I'll give you this image And you put it on your wall and put people out So to work around that problem Of having To choose different authentication engines you define a common API So inside application control we ask people to define in a forum user That just points to the current user object of the request simple like a lot of engines use current user Or a maybe current person or current account or whatever just forum user. It's the point to some object That is the current user Into the initializer for forum We ask you to tell us what the user class is and it must be a string because if it's a class and there's some loading problems that go on So we say look, this is the user class and we use this to determine the associations between topics and parts We also ask you to define a 2s method on the user class. That's it three things This allows people to use things like off logic or device Or something completely custom That's not like how I wish it was So the second thing we've had a shot or lost how do we do authorization? So I've been in on this so I just thought I just do I just do can can So we define methods or use methods in our views like if a user can read a category Then we let them do these things How we do this is that we have a module called default permissions that's automatically included into the user class Or the thing you tell us what the user class is And this has some methods to find out by default I can read forum category and can read forum forum These methods just simply return true Like that But if you don't want to use the defaults, you can just override them in your user class So you can get it to query permissions tables if you want or you can query a YAML file Or if you have a Soap interface or LDAP whatever I don't care you can redefine the methods So how this works the forum is that we have an ability class defined inside the module forum We include can can ability initialize a new user objects, and we just define the permissions So we say If you use a can read a forum category Then the can read forum category on that user object returns true simple So we use the forum music class Initialize a setup here, which is good Inside forum application controller. We define an ability if we define a current ability method Which simply returns form ability A new instance of that With the argument of forum user and that's then how we can do all that all authorization Inside the engine without having to massacre one of the applications using so the application can use Whatever else they like and so we have a simple yeah for that One of the other problems we came across was theming How like when we were writing forum initially we were trying to think of how we do theming because a lot of different forum systems have different themes In rails 3 this wasn't so possible but in rails 3.1 with the asset pipeline. It's actually quite easy Inside the layout for the engine you have a star sheet link tag and you used to do forum theme twist But where is the star sheet located? It's actually it's located inside an engine So you write another engine you create another gem That's called a forum theme twist and in they define our rails engine class By inheriting from rails engine you add the asset paths to the load path for sprockets And so when you load forum theme twist, it's going to look up in that engine and find it Which basically means a browse engine rocks So inside forum theme twist we have this path Assets star sheets forum theme twist and just works so you can use JavaScript and images too if you like The final problem that we tackle forum was that we were trying to do Make the slideshow and set up an easy process Originally, it was you would add the forum gem to your gem file Of course, you would need to run bundle install and install migrations copy over the migrate. Um, sorry run the migrations Create the initializer by following the reading add forum user method to your application controller add the 2s method To use a class go into the console and create your first forum about the forum engine had Wrath at whatever path you want and then just pray that it works It's very magical We changed that we actually got it to be that when you we have to add forum to your You have to add forum to your gem file still you still have to run bundle install You haven't used forum before But then that's when it diverges you run rails you forum installed and you answer two quick and easy questions What is your user class and what is your current user method all forum needs to know And that works assuming that you have a user model So with all these lessons that we learned from like writing the engines chapter and writing forum I took them into spree one dot oh And there's this guy called josh ovens who's helping out the forum From one day he posted to the spree user group Like a four sentence email saying like does spree support Does spree work with refinery? Uh, why doesn't it and then there was this back and forth josh ovens asked me to come Into that thread and reply I ended up writing a page and a half reply And so shulman was like hey like shulman scurfield was like hey you want a job? I was like sure why not So my job was basically was sitting cafes and namespace crap out of spree That's it shulman was like go do it So previously we had the php style namespacing the spree core like company name The fuss we changed that now we're at spree and then double column core and spree off Inside each of these components though we have models and controllers The original idea when I pitched was that we might have the models namespace under their respective components So you would have spree core product just getting a bit long So we thought well, why can't we just call them spree product? Makes more sense still maintains a namespace by having that core namespace there. There's no point There's no other product model in spree. So why are we namespacing? With this namespacing work, this is the common diagram you've seen before If your application has a product model you can still access that and you can still access spree's product model So what? That was namespacing The difference between spree and forum though is that forum is a single component And to mount forum into your application. It's a simple thing. It's one to one You have the routes that are drawn on the engine and then you mount the forum engine at a specific path Spree is a different beast entirely. It's made up of five different paths This means that you need to mount five different engines into your application This means that you need to draw five sets of routes in spree So and all five sets of routes need to be mounted into your application Then if you were to happen to write a spree extension, you would need to mount every single extension one by one No fun You'll also need to know Where the specific routes and spree are so you need to know the route path is inside spree core And you need to know that login path is inside spree off And this is all really funny You're like, how do we fix this So we play around a bit the golden part the absolute golden part is to have one line amounts everything just like in the lunch Device has one line forum has one line Spray now has one line So we mount spree in a specific path and that way you don't need to know where the routes are So you just do spree root part that goes to the root path of spree or spree login path that goes to the login path of spree The way we accomplish this is that inside each individual component we prepend its routes to spree cause routes So spree off and spree promo and spree dash don't have their own routes. They prepend to cause We could have instead Done this we could have repended to the core engine Which would mount the engine as spree but that wouldn't work because spree off still would have that route prefix So have spree off login path and so we couldn't do that So now what happens with spree is that everything mounts into the core And then core goes into app That was Nice easy solution. That's the golden part The next thing that you want to ask me to do is fix everything You have a whole bunch of failing tests. So in fact at the moment 0.70 stable is not so stable. It has failing tests And I consider failing tests to be broken code One of my favorite failing tests was this one quite simple You have spree product controller Cancel list of products and all you do is you get the index action You assume that the index action works. There's there's some more code, but it's not relevant to this story So what does this do someone What does this do does it pass does it fail what does it get requested and then what Right it doesn't pass Wrong You're all wrong Even though we had the route defined It would tell us that no route matches spree product control index. You know, no, it's right there. You stupid computer. It's right there You're like, what the fuck So I went on to my uh, like my sanctuary And I somehow found this outside. I don't know maybe it's thrown at me something And he said the workaround is quite simple instead of get your action and your parameters Use get show your parameters and then use route post. So who's seen this use route option before anyone? One one person one person has seen this use route option That's kind of obvious right you use route everyone uses use route All we have to do is add this to every single get or post or put or delete Thing in spree. We have a have another file that I put controller hacks that overrides the get put post and delete methods Just automatically adds this So I was like, how did this guy know? Is he god? So I was in rails because That's how people find out about things. They grab the source with the active source and it's in three different files It's in route set. It's in routing test. It's informed helper test And all three files have no comments and no description As I said before rails documentation is So after that little problem, we fixed everything inside the spree master and one no stable passing form is passing So good implemented a whole bunch of bug fixes as well Thanks to anyone who's anyone here who's contributed to the spree. So if you're interested in using spree It's right now. You can use it go ahead. Please do And um, I'd like to apologize because I'd like you I said that there's only 300 lines of documentation for rails engine Really really really really really really really sorry I actually wrote a game started with engines guy. You can go and read it. It's 800 lines low it covers everything that I have covered in this talk It's on the edge guides Even includes testing. I didn't put testing in this talk, but it covers testing engines So if you're looking to generate if you're looking to generate if you're looking to write an engine Please read this guide first if you have any problems with it hit me up on twitter get hard emails smoke signals, whatever Awesome. Thanks guys