 Okay, cool, that sounds like I'm mic'd for sure. Hi guys, sorry we're getting started a little late technical difficulties at a tech conference, makes sense. So, hi, I'm Sasha, Sasha Gradsons. I'm a Chicago native, a DevVuCamp graduate, yeah. And I've been working as a developer at a consultancy called DevMind Software, also in Chicago, and San Francisco. If you wanna find me online, I am sassy grody pretty much everywhere. Okay, yeah, welcome, thanks for coming to build a blog in 15, more like 30 minutes. This is the webpacker edition, and I also just added GraphQL to the title because that's what we're using, which has been a common theme throughout the past few days. Another common theme I've found is like a theme of nostalgia about Rails, with like the history of Rails track and all that. So, this is also fits in there. It's an ode to DHH's presentation of the same name, where he presented Ruby on Rails to the world back in 2005, I believe. So, there he live codes this presentation where he builds a blog with posts, comments, pagination, and like adds some tests at the end, and he does it in 15 minutes. So, that's been like blowing people's minds for over a decade, and like has been a tutorial and reference since. So, what is this talk? This talk, we're also going to build a blog. It's not going to be as revolutionary or fast, hence the title, and we're gonna be using a React front end, a GraphQL back end, and I'm gonna show how you get that all hooked up in a single Rails application. That link is not active yet, so sorry about that, just ignore it. It will be on GitHub as soon as I'm off the stage. Okay, so welcome Webpack. For the past few years, the company has been building with these tools, and I remember like the first time we set up an app, we had a front end app and a back end app, one was React and one was our Rails API, and it took a full work day, if not longer, to get it all hooked up and talking to each other and displaying data on a page, just because like the configuration like added so much overhead. But then Rails 5 was released and Webpacker made its debut and changed everything. You could initialize a Rails app with pretty much no configuration and have React, or I'm sorry, we could have like any JavaScript library just configured to run in your application. So that was great. I have to be honest, I'm working without my speaker notes, so that's why I'm like kind of struggling right at this moment. But anyway, Webpacker came out and it was awesome. I think that's all I had to say about that. So what are we doing? I wanna just go over what our tools are right now, so we're gonna use React to build all of our views. The definition of React from the DAX is a JavaScript library to build user interfaces. Yeah, it's a view library, it is a client, it is a front end, all those things. What is GraphQL? Again, from the DAX, a query language for your API. What does that mean? I think the thing to think about here is that React and GraphQL were created by Facebook and they, as they're becoming one of the biggest companies in the world, faced some problems with traditional REST APIs and jQuery madness kinds of things. So they created these libraries. The most notable thing about GraphQL is that it uses a single endpoint. This is not a single endpoint. This is a RESTful API. It's a screenshot straight from the Rails doc so it should look familiar. So yeah, the way RESTful APIs work is you have different endpoints for each action you want to perform in each view you wanna show. So if I wanted to get a single article, I'd have to make a request, the Htt request to get article slash ID past the ID in a parameter somewhere. And what I expect back from that from a Rails application is a full active record object which would be the ID, any fields I migrated onto it and created that updated timestamps. So that's a lot of data and I might not always need that. So GraphQL solves this in having a single endpoint. So here we see post slash GraphQL. That is the only way to get data in and out of your backend. So the way that works is you make your Htt request to the single endpoint GraphQL and you pass in a GraphQL query that looks exactly like this, shaped like JSON kind of structure. So if I wanted to get the same data I just mentioned before from Graph API, I'd say I need a post with an ID and then the specific fields of data that I want to display on the page. So in this case, I'd only get a title back. I wouldn't get ID or timestamps or anything else from that object. So that's really nice because it is small contained pieces of data and it makes everything very predictable. How does it work? This is a big talk so maybe you've been to a GraphQL talk in the past few days and if you have that's awesome. But just a little overview, there's the idea of types of mutations in GraphQL. So a GraphQL type corresponds to some piece of information in the backend that you want to expose to the front end. So in our case today, it's going to correspond to an active record model. And the mutations specify which parts of the data in the backend you want to change. So because you only have a post request that you can make you have to say whether or not you want to get data or you want to change data via a type 4 mutation. Okay, so the other reason this isn't going to be as fast and cool as DHH's talk is because I've already done some setup. I did the Rails new command with the webpack extension where we're going to use react as our front end. That took close to three minutes to run in this Wi-Fi so I'm glad I did that. I also added the GraphQL library in the gen file and I bundled, hopefully, everyone's seen a bundle. It's not very exciting. I did run the Rails GGraphQL install command which is actually a really cool command. I'm sorry, you don't get it yet today. But that's the thing that basically sets up the whole API. It adds a line to our routes for this post GraphQL endpoint. It sets up the controller with a single method for that endpoint to hit and it sets up some root type mutations for us. Pretty nice. I'll add that in a second. I added a model already, the post model, and I seeded some data because you also don't need to watch me do that. And that's so loud. I added a single view page so that when we hit logo host slash root, we don't get the Rails friends image, you don't know how cute it is. We don't need it. All right, that's it. That's it for these slides. Get out of here. All right, the first thing I wanna do is I wanna start the server. So because we have our webpack server and our Rails server, we have to start both. So we'll say Rails server. How's that font size, everybody? Good. Nice, nice, thanks. Okay, and then on this side, we're gonna use the built-in command which is dot slash bin slash webpack dev server. You can add a shortcut in your package JSON to get like a faster, shorter thing, but I'm gonna keep everything as default as I can. Okay, so it looks like those. Ooh, oh my God, that's like a lot of tabs. Oh, there it is. Okay, cool. So localhost is up and running. It says hello from the index. I added that to my single Rails server. Rails view page. So if I go to my views, I've got this index. Hello from my index. So this is a Rails, a normal Rails view. It's ERB with a little bit of text in it. But like I said, I want all of our views to be built using React. So I'm gonna go try to find my React files. Is this, this is probably like impossible to see, so sorry. But on the side, we've got a normal app structure in this file system tree. But the webpacker command, the installation process, added a JavaScript folder and it has a single folder called packs and two files in it. The one we're gonna be using today is called hello react. So this was just generated for me. I haven't touched this since I ran Rails new. And this is a React root node is what we like to call these where like you are finding a document, appending stuff and that's where all of your React content is going to live. So they've got this demo here and it says at the top, like, you know, grab this, whoo, tag and put it in any of your layout. So I'm gonna put it in this application thing that I'm calling my layout. So JavaScript back tag, hello react. So if I refresh the page, I get a new piece of information there and it says hello react and that's coming from the component that was generated for me. So here's this hello and it's like calling props.name and name is sent down here. So it's like, hello RailsConf, save it, go back. I didn't hit refresh, it's hot reloading for me which is also really great. Hello RailsConf. So basically what I'm just proving here is that React is loading and I didn't do anything really which is awesome. The next thing I wanna do, so we're building a blog, right? I need to build a blog container. So I'm gonna make a file called blog container. Just.js. The other thing I'm gonna do a lot of to speed up time is you snip it. So like, bear with me, you don't need to see me type out all these words and the fat finger everywhere. There will probably be some typos, so watch out. All right, so I'm going to define a ES6 class called blog container that extends React component. I'm importing the component from the React library itself. So this is a React component. What they look like, they have this render function because the whole point of a React component is to render stuff. So this is just a JavaScript function and it has this explicit return because we're in JavaScript. In this, what it's returning is called JSX and JSX is the templating language used in React. It looks a lot like HTML, so it's really easy to write in but it has full JavaScript capabilities and a lot of built-in properties that are very helpful to us. So I have defined this blog container but I'm not rendering it anywhere. So I wanna render it into my root node, my blog container, I'm gonna import from blog container and this stuff like, I mean, I'm just gonna delete it for now, we don't need it. Instead of rendering the generated little tiny component, I'm going to render my blog container. So at this point we should see whatever is in the blog container on the page. Yeah, okay, great, it's very good. It looks still so bad because of this thing, I'm gonna get rid of this and now we have a full, I mean, our only view is a React view and so we're gonna just continue to build only in the blog container. So what's a blog without post? It's nothing. So we need to find a way to get some data onto this page and the way we're gonna do that is by making a request to our GraphQL backend from our client here. So we need to go back to our GraphQL and set some things up. So as I mentioned, the GraphQL installation added this GraphQL folder and then two folders within for mutations and types. That's where we're gonna keep our data, our definitions of these GraphQL types. So if I look here, there's a query type, it's a mutation type with a bunch of test fields that we could play with those but I'm gonna skip over them for now. What I need is I need something, I need a new type. These things are working off of default type strings so this test field is returning some kind of default GraphQL type of string. As you can see here, that string is Hello World. So I needed to define a new type. Mentioned everything is built off of types and mutations. So there is luckily a command for this as well, GraphQL object. So this will be a post, capital P post with a title. These things are going to correspond to what's in my database because that's what I want to be available to me on the front end. Quite cool, so it made a single file called post type. I'm gonna go look for that, here it is. So it just generated this big thing for me which is awesome and I know that I have a post type now, a GraphQL type called post type and it has these fields on it. So what do I need to do with them? I need to expose them to the root layer of my API. So the way you do that is you define a field here and what do we want to call that? I'm gonna call it posts. I want a list of posts so I'm gonna say this new type I just added is post type and then part of the DSL like the GraphQL library comes with this two list type method. So that'll basically just return an array of post types. However many I'm gonna get my resolve block. Oops, not that, list of posts. So the other really cool thing about GraphQL is that it's pretty much self-documenting based on just what I write here. You know what you're gonna get because I just said I'm gonna return a list of posts. So this is a resolve block, it's a lambda and it has these three things that are coming back from the GraphQL controller itself. But it doesn't really matter because all I want from here is an active record call that is post.all. I want all the posts. I don't care what order they're in, I don't care anything about them. It's what I want. So there's another really cool thing about GraphQL. I don't know if I mentioned this yet, I can't remember. But it did also initialize with this other route called GraphEQL or GraphQL, whoever you are, however you want to say it, it's fine. And this is an in-editor IDE for you to test out your queries that you write. So like the query we just wrote, is that okay? Okay, that's the best kind of feedback. Okay, cool, so well, I'm feeling like I hadn't written that yet. So this is a documentation explorer, it's a great name for it because that's exactly what it is. You see it has a root types here of query and mutation. So I can click into this and say like, what do I have available to me in my GraphQL API? That is posts, two fields. There's posts and there's test field. And we can see over here on this root query type that we have these two fields, posts and test fields. So like I said, I don't think I've mentioned anything about this, this is a GraphQL query over here. This is exactly what we're going to ask the database for. So I start typing, it's very, very helpful and that it tells me what I can type basically, like I can type in A and it'll say like, oh, there's nothing with that, what do you want really? And they're like, I want titles. So it looks like I'm getting some data, right? There are a couple of blog posts that I seeded as I mentioned. Two of them are just things that I wrote. One of them is a real blog post from the DevFind blog. So that's great, like this is a JSON looking object. I feel like I know how to work with that. And I'm only getting titles, which is exactly what I asked for. If I wanted content as well, I'd have to put content in there explicitly so that the API knows what to get. You know, we could get all three of the things ID, but I really think this, I'll put some titles right now. Yeah, so what do we do with this type? What do we do with this query? I'm actually trying to remember. So we're going to go to our JavaScript again. We're going to flip back to our React. This is our blog post container, it doesn't do anything. And really what we need it to do right now is go make a request to our API. So I'm going to define a function called getAllPosts. Again, so these functions are available to like within the component. They're just scoped functions to this blog container component. So getAllPosts. I didn't want to add any more libraries. This is just the basic config. So we're going to use the fetch API. Here's a nice big snippet for you. So the fetch API is just built in to React right now. It's just great. So you can make any kind of HTTP request with the fetch. You just fetch the URL here, GraphQL. The method, we know it's going to be a post, headers. And then in the body, this is where you're going to set your GraphQL query. So you just kind of, you give it a key, give it a string. And then I'm going to literally copy this GraphQL query I was playing with and graph EQL and paste it. That's what I'm going to do. And then I'm going to resolve the promises, fetch terms of promise, you have to resolve it once to JSON and then you resolve it again. And we'll see what we get in this last part here. Ooh. Okay, so I'm not hitting the debugger because I'm not actually calling this function anywhere. So where do I want to call this function? I want this data and the fetch request to have been called before the page render. So components have these things called life cycle methods. And we're going to use component did mount. There are a couple of them and then they're totally worth reading about and they're very helpful. Component did mount. And I'm going to have component did mount call get all posts. So this will call before, ooh, call so fast. It'll call before the render loads as you kind of just saw there. Like it's just like, pops open here. So I'm in my debugger. This is too big to even operate in. What do I have? So I have this response data and it's got posts. Yes. Okay. So I've got an array of posts coming through at the end of that fetch, which is awesome because that's exactly the data that I want to show in my app. So what do I do with this data? I'm here. I've got response data posts. That's an array. So I need to have that accessible to the render method. The way I'm going to do that is use another built in react function called state. So our react property. I'm not really sure we want to call this, but state is built into every react component as well. So you can pretty much hold anything you want in state. I'm going to hold posts here and just set it as an empty array. So this is like my initialization of the state of the react components. Like there's nothing there. I can't just call this.getallposts here except how state works. So the order in which things are going to work is the components going to load from the root node. It's going to call state. State will be set to this.state.posts as an empty array. So component did mount is going to call next and it's going to call this.getallposts that'll call our fetch method. And at the very end, we're going to reset the state, reassign that empty array into actually having data. So let's say posts, response data posts. So then state is available to every part of the component. So I can say, oh, not that. Post equals this.state.posts. So this const should be an array of those posts from the database. And then I'm going to just iterate over them in the JSX. So to evaluate any JavaScript you use two curly braces in JSX. And we can just use a normal ES6 map for a single post. Can you give it an index syntax? Looks okay. Oh no, that's going to be too big. Oh no. All right. So then, right, it looks like HTML, it's not HTML, JSX, so you do curly braces to evaluate the post title. Cross your fingers guys, what do we have? What do we have? Oh yes, we've got a list of titles. Oh yeah, okay, great. So like that still feels good. I've been doing this for a really long time and it still feels very good. And like such a relief. Okay, what do we want to do? Actually I want to show the post content as well. So like everything's going to be on the single page. I don't have a router, so we're not going to have like a show page. It's just all going to be right there on the single page. So I'll do this. Okay, great. Adjacent JSX elements must be wrapped in a closing tag. Learning a little bit about JSX here. That just means that you can't have two siblings like right there next to each other. They need to be wrapped in something. I'm going to wrap them in a div. You can wrap them in whatever you want. And then that should load properly. But we don't have any content. Maybe you know why, but the reason we don't is because I'm not asking for it yet. The GraphQL query is like, you didn't ask for content. I'm not going to give you any content. So I need to put it in the query and I have to come back. Now we have some content. So that looks like garbage, but there's no styling and there's not going to be in this talk. So just hold tight, at least there's data. Cool, okay, so we are rendering blog posts. I think that's really great. So we know how to get database from our backend. Now we need to learn how to change some data. So I know this is called a crud app, but we're going to go out of order and we're going to do the D of crud first. So we're going to delete. Really like when it comes down to it, the other thing about the GraphQL is that you only have a mutation in a query. You don't have crud. You don't have get and posts and put some patches and those deletes, you only have one thing. So it's not exactly crud anymore. Like the definition of crud is a little different here, but let's do this. What am I doing? We need a delete link. So I know that the delete link itself is going to make another fetch request. So just to keep it like contained, I'm going to make a new component for delete link. Call it delete link. And I'm just gonna put the word delete there. I'm gonna give it a class, which is link. Then I'm gonna render it. I'm gonna render it in the blog container and port delete link. Delete link. I'm going to render it right below the post title. Ah, yeah, okay. So now each row of posts has a delete. It does not look like a link. I'm going to just very quickly change that because I think that's too crazy. That one will say links I usually bloop. So the other really cool thing about having your React app in your Rails app is that you get the asset pipeline, which we all know and love and I like that a lot. So cool, this thing doesn't do anything. It's a div that's styled to look like a link. What I want to do is give it an on click handler to call a function called like handle delete. I'll define handle delete as a function again in this component. And we're gonna make another fetch request. So the same thing, the same structure, but now we need to make a different kind of query. Essentially here we need to make a query for mutation. And we don't have any mutations. So we have to go back to GraphQL now. Let's see, GraphQL mutations. Yeah, mutations are empty. So I'm going to create, there you'll see GraphQL mutation. And it's gonna be delete underscore posts. That's just the way it's going to be. So that added a couple of things here for us. It added a file under mutations, delete posts. So this is not the same kind of definition we've been seeing the post type itself was just a GraphQL object type, whereas the delete post mutation is built off of a different module. But it looks kind of similar in a lot of ways. So it's actually really nice. The other thing it did is it added, oh, I'm just gonna delete this. Yeah, I'm gonna remove you. It added the field for me on the mutation root type. So delete post has a field now on this mutation type. Okay, so let's see. This thing has directions for me. It says to do, define your return fields. So it's suggesting I return a post, but because I'm deleting here, I'm actually just gonna return a message and I'm gonna use the default GraphQL type of a string because I'm just gonna say, at the end of this, if all goes planned message post was deleted, that's what I wanna see somewhere, probably in a flash message eventually, but maybe just in the console for now. And then the next thing is to do, define argument. So input field named type string. This also doesn't feel quite right because when we delete, we usually delete by finding things by ID and then deleting the object that we found. So the input field is going to be an ID. And again, we can use the generic GraphQL types of ID to do, resolve the function. So again, let's just do some active record stuff. Let's find by the ID, which I'm gonna pass through in the args, kind of like how we saw in the query before. And then we'll just, I'm just gonna destroy that post. No questions, I spelled that wrong. Destroy, cool. De-story happens to me all the time. Okay, yeah, so we're just gonna, we're just gonna assume that works. I'm not gonna, I'm gonna put the thing. So let's see. We can use GraphQL to test that out again. If I refresh this page, look at our mutations. We have a single field for delete post. It takes input. So I think the same way that I created the query over here, I can do the same. Start typing delete post, input, and then put type as an ID, right? So I'm gonna delete the first one. Let's see. Okay, so I just have a guess there. I assumed there was a post with the ID of one, but it does say that the post was deleted. So if we go back to our front end and we refresh, there are only two, which is exactly what I wanted. Cool, so I'm gonna do the same thing where I copy this mutation, put it into the delete link query. I don't wanna hard code this. So like somehow I need to get the post ID. And the way I'm going to do that is if I go back to the blog container, we're iterating through these posts, right? So this is like a post row and the div itself is contained to a specific post. So I can send in a property called post ID, which would be post.id. This isn't gonna work immediately because I'm not requesting the ID. So if I want to do that, I have to put it here. So now I'm calling all three of the fields that are available to me. I'll have that in my response and I can send it through to the delete link. So the delete link can access these kind of properties via a call that looks like this, this.props.postid. So that's how you can pass data from your parent down to your child. And that's a very common pattern and react precisely for this kind of demonstration. Let's see, so we're gonna get our response back. Hopefully it's good. Hopefully we get a message here, right? So console out the message. We don't really have state in this component. This component is just a link. So I'm not gonna try to set the state here, but I do really want to reload the posts at the end of this because I don't wanna hit refresh when my posts are deleted. So I can actually, it's demonstrated. Let's see where we're at here. I open this, oh, okay. Well, that's just a warning. I'll fix it in a second. If we hit delete, uh-oh, got undefined because it didn't work, right? Oh, it did work, wow. Okay, so now only one post, the delete is working. I am surprised. Mostly I'm just thrown off by that huge gross warning. I'm gonna fix that. It's bad warning is saying that when you iterate over things, you need to pass in a key with a unique value. So I'm gonna use the index of the map. That'll be pretty unique. That warning is gone, which is great. If I hit delete again, hit refresh. Now I don't have any more posts to work with, so I have to re-seed in a sec. Okay, great. I'm actually gonna just see it again. Let's do it. Let's get a bunch of them. Cool, okay. So we have six, can I count? Yeah. Okay, so right. I'm hitting delete and then I have to hit refresh to get like a new list of posts back because the front end doesn't know what to do yet. So if I go back to my delete link, I've already written this function somewhere, right? The this.getall posts, but that is not available to this component because that is defined in its parent. So much like how we passed down the property for post ID, I'm gonna pass down this function as a property. So it's called getall posts. So then I can go back to my delete link and again call it via props.getall posts. So not, you can pass like pretty much anything down from a parent to a child via props there. That's a function. We pass like strings, you can pass whatever you want. Let's see, see where we're at. I close that and hit delete. Yes, woo! Okay, so that thing is deleted out of the database and I'm gonna do a couple more because there are too many. Awesome, that's deleting. Yeah, I'm like stunned because I still have time and like every time I've gone through this, I've run out of time before I got here. So cheers to talking really fast and for things going pretty well. Let's see, I guess we should just keep going. We may as well do create. Oh, I don't know, that sounds like kind of ambitious. Well, let's try it, let's see how far we get. I'm going to, yeah, I'm just gonna like check all this out. So everything on here is going to be in a branch eventually. I'm sorry, not a branch, a get repo. And everything is like branched out pretty precisely. So if you wanted to check out different spots of the tutorial that will be available, you could start from like wherever you wanted. They build on each other. So like in this tutorial, it's gonna go C first, C of crud to, or R of crud, C of crud, to U of crud, to D of crud. I find that to be like the most normal way to build your application. But I started with D today because why not spice it up? But if we want to see C, let's just like check out C of crud, start. No, let's just see what it looks like completed, why not? Let's go to all the branches. Okay, so here I did add a form. This form lives in its own component. So again, it's just a little component. It has some state for title and content. This is like exactly how the docs of Free Act tell you to make a form. So there's plenty of information about like why this is how it's set up. But forms again, look a lot like HTML, but they have all of these handlers and properties that help like set the state and make changes and submit data. So these inputs, this on change, we're calling this handle input change. And handle input change is just resetting the state. So for us, when we are creating our mutation, we're gonna send along the title and content from the state that is the title and content that is here. So like, oh, right. Okay, so nothing's happening because we don't have a create mutation. So let's see, oh shoot, yeah we do, I forgot. Okay, so I've already created my create mutation. Let's just go look at it, create post. So I did this the same way I made my delete post, which was RailsG GraphQL mutation, create posts. This one, you can see like has a return field for the post type, unlike delete, which was return field of a message, I think is what I did. This one has input field for title and content. And here the resolve block, again, active record, whatever you wanna do for a mutation is we're gonna create a post. So we create a post with the title and content that comes through in the arguments again. And actually that's like, oops, invisible to us here. This fetch has a mutation called create post title content. They all start to look a lot alike, if you can't tell already. Let's see, let's check out, let's go. This might be the end of it. So this might just be like everything working. So we have this delete, delete things and I can edit. So the way it chose to edit for the sake of this demo was to do it on the same page, right? Like I said, I don't have a router. I don't wanna like have a page just to view an edit form. So you can edit and oh, tips for petting every dog on the street or something like that. I wrote that. You can edit this, just be like, whoo, that says few, but I do mean whoo. And then it edits in place. So that is more or less the completed CRUD application that I meant to demonstrate today. And that's it actually. So thank you so much for coming guys. I had a blast, I hope you did too.