RailsConf 2018

Build A Blog in 15 (more like 30) Minutes: Webpacker Edition

Build A Blog in 15 (more like 30) Minutes: Webpacker Edition

by Sasha Grodzins

In the video "Build A Blog in 15 (more like 30) Minutes: Webpacker Edition" by Sasha Grodzins, presented at RailsConf 2018, the speaker guides the audience through a live coding session where he builds a blog application using a Rails backend combined with a React frontend and a GraphQL API. This session serves as a modern homage to David Heinemeier Hansson's original talk on Ruby on Rails, where a blog was built in a mere 15 minutes. However, Grodzins notes that his version is unlikely to be completed that quickly due to added complexities.

Key Points Discussed:

  • Introduction to Technologies:

    • Grodzins introduces the main technologies used, which include Rails for the backend, GraphQL for API communication, and React for the frontend views.
    • He explains that GraphQL was created by Facebook to solve issues commonly found in traditional REST APIs, notably by providing a single endpoint and allowing clients to specify exactly which data they need.
  • Project Setup:

    • The initial setup of the Rails application with Webpacker is discussed, highlighting the significant reduction in configuration time thanks to Rails 5 and Webpacker.
    • The speaker executes the rails new command with the Webpacker extension and explains the necessary bundling and setup steps performed at the beginning.
  • Creating the Blog Structure:

    • The creation of the blog container and the integration of React components are demonstrated.
    • Grodzins explains how to structure components and utilize JSX for rendering views, emphasizing the component lifecycle methods, particularly componentDidMount() for data fetching.
  • GraphQL Implementation:

    • Grodzins walks through setting up GraphQL types and mutations, including creating a query to fetch blog posts and a mutation for deleting posts.
    • The use of a self-documenting nature of GraphQL is highlighted, where developers can interactively explore GraphQL queries.
  • State Management and Data Display:

    • State management in React is addressed, where the fetched data from GraphQL is set to state and rendered in the component.
    • The speaker demonstrates listing post titles and contents by querying the GraphQL API.
  • CRUD Functionality:

    • The implementation of create, read, update, and delete functionalities is completed within the live coding session, showcasing how to modify the application without needing a page refresh.
    • A brief mention of adding form components for creating new blog posts and inline editing features of existing posts is provided.

Conclusion:
Grodzins successfully builds a fully functioning blog application, demonstrating the ease of integrating Rails with React and GraphQL. The session illustrates the modern web development stack's capabilities while educating attendees on best practices for structuring React applications within a Rails framework.

00:00:12 Okay cool, that sounds like I'm miked for sure. Hi guys, are we getting started a little late due to technical difficulties at a tech conference? Makes sense. So, hi, I'm Sasha Grodzins. I'm a Chicago native and a Dev Bootcamp graduate. Yeah, yeah!
00:00:22 I've been working as a developer at a consultancy called Dev Mind Software, also in Chicago and San Francisco. If you want to find me online, I am Sasi Brody pretty much everywhere. Okay, welcome!
00:00:37 Thanks for coming to 'Build a Blog in 15 (more like 30) Minutes', this is the Webpacker edition. 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.
00:00:50 Another common theme I found is a theme of nostalgia about Rails. I would like the history of the Rails track and all that, so this also fits in there. It's an ode to DHH of the presentation of the same name where he presented Ruby on Rails to the world back in 2005.
00:01:08 I believe it was then that he live-coded this presentation where he built a blog with posts, comments, pagination, and added some tests at the end. He did it in 15 minutes, and that has been blowing people's minds for over a decade. It has served as a tutorial and reference since then.
00:01:25 So, what is this talk about? We're also going to build a blog. It's not going to be as revolutionary or fast, hence the title. We're going to be using a React frontend and a GraphQL backend, and I'm going to show you how to set that all up in a single Rails application.
00:01:45 That link is not active yet, so sorry about that, just ignore it. It will be on GitHub as soon as I am up at the station. Okay, so welcome Webpack!
00:02:05 For the past few years, my company has been building with these tools. I remember the first time we set up, we had a frontend app and a backend app. One was React and the other was our Rails API. It took a full workday, if not longer, to get it all hooked up and talking to each other and displaying data on a page because the configuration added so much overhead.
00:02:24 But then Rails 5 was released and Webpacker made its debut, changing everything. You could initialize a Rails app with pretty much no configuration and have React.
00:02:38 Sorry, we could have any JavaScript library just configured to run your application, so that was great!
00:02:51 I have to be honest, I'm working without my speaker notes; that's why I'm struggling a bit at the start. But anyway, Webpacker came out, and it was awesome. That's all I wanted to say about that. So what are we doing?
00:03:10 I want to just go over what our tools are right now. We're going to use React to build all of our views. The definition of React from the docs is a JavaScript library to build user interfaces. Yeah, it's a view library.
00:03:24 It is client-side as a frontend, although since what is GraphQL?
00:03:37 GraphQL, again from the docs, is 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. As they became one of the biggest companies in the world, they faced problems with traditional REST APIs and jQuery madness.
00:03:58 So they created these libraries. The most notable thing about GraphQL is that it uses a single endpoint, which is different from RESTful API.
00:04:14 In a RESTful API, you have different endpoints for each action you want to perform and each view you want to show. So if I wanted to get a single article, I would just make a request to 'articles/ID' and pass the ID as a parameter.
00:04:32 What I expect back from a Rails application is a full Active Record object, which would be the ID and any fields I migrated onto it and created at/updated at timestamps. That's a lot of data, and I might not always need that.
00:04:50 GraphQL solves this by having a single endpoint.
00:05:02 Here we see 'post/graphQL'; that is the only way to get data in and out of your backend. The way that works is you make your HTTP request to the single endpoint GraphQL and you pass in a GraphQL query.
00:05:19 The query looks exactly like this, shaped like JSON or any kind of structure. If I wanted to get the same data I just mentioned before from my Graph API, I would specify I need a post with an ID and then the specific fields of data that I want to display on the page.
00:05:37 In this case, I'd only get a title back; I wouldn't get the ID, timestamps, or anything else from that object. So that's really nice because it returns small contained pieces of data, and it makes everything very predictable.
00:05:58 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 are the ideas of types and mutations in GraphQL.
00:06:07 A GraphQL type corresponds to some piece of information in the backend that you want to expose to the frontend. In our case today, it's going to correspond to an Active Record model.
00:06:22 The mutations specify which parts of the data in the backend you want to change. Because you only have a post request you can make, you have to say whether you want to get data or change data via a query or mutation.
00:06:37 The other reason this isn't going to be as fast and cool as the DHH 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 frontend. That took about three minutes to run in this Wi-Fi, so I'm glad I did that.
00:06:56 I also added the GraphQL library to the Gemfile and I bundled. Hopefully, everyone has seen a bundle; it's not very exciting. I did run the 'rails graphql:install' command, which is actually a really cool command.
00:07:12 I'm sorry you don't get to see it today, but that's the thing that basically sets up the whole API. It adds a line to our routes for this PostgreSQL endpoint and sets up the controller with a single method for that endpoint to hit.
00:07:28 It sets up some root types of mutations for us, which is pretty nice. We'll see all that in a second. I added a model already, the post model, and I seeded some data.
00:07:42 You also don't need to watch me do that, and it's not so loud. I added a single view page so that when we hit localhost/root, we don't get the Rails friendly image. You don't know how cute it is, so we don't need it.
00:07:57 All right, that's it for these slides. Let's get out of here!
00:08:05 The first thing I want to do is start the server. Because we have our Webpack server and our Rails server, we have to start both.
00:08:18 So, we'll say 'rails server'. How's that font size? Everybody good? Nice, nice, thanks! Okay, and then on this side we're going to use the built-in command which is './bin/webpack-dev-server'.
00:08:30 You can add a shortcut in your package.json to get a faster, shorter thing, but I'm going to keep everything as default as I can.
00:08:45 Okay, so it looks like those. Oh my god, that's a lot of tabs. How are they?
00:08:57 Cool! So localhost is up and running. It says 'Hello from the index'. I added that to my single Rails view page.
00:09:06 So if I go in my views, I've got this index of my index. This is 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.
00:09:22 So I'm going to try to find my React files. Is this...? This is probably impossible to see.
00:09:31 I'm so sorry, but on the side, we've got our normal app structure in this file system tree. The Webpacker command that the installation process added a JavaScript folder and it has two important folders.
00:09:41 The first one is called 'packs' and two files in it. The one we're going to use 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.
00:09:56 This is where you are finding a document, appending stuff, and that's where all of your React content is going to live.
00:10:07 So they've got this demo here and it says at the top, you know, grab this tag and put it in any of your layouts. So I'm going to put it in this application thing that I'm calling my layout.
00:10:21 So, JavaScript pack tag hello. Yeah, so if I refresh the page, I get a new piece of information there that says 'Hello React' and that's coming from the component that was generated for me.
00:10:33 So here's this hello, and it's calling props name, and name is sent down here.
00:10:48 Hello, RailsConf!
00:10:54 I saved it and went back. I didn't hit refresh, and hot reloading works for me which is also really great.
00:11:02 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.
00:11:10 The next thing I want to do is, since we're building a blog, I need to build a blog container. So I'm going to make this file called 'blog_container.js'.
00:11:21 The other thing I'm going to do a lot of is just speed up time as you snip it. So bear with me; you don't need to see me type out all these words and fat-finger 'L' everywhere.
00:11:35 There will probably be some typos, so watch out. All right, I'm going to define an ES6 class called 'BlogContainer' that extends React.Component.
00:11:52 I'm importing the component from the React library itself, so this is a React component. They look like they have this render function because the whole point of a React component is to render stuff.
00:12:04 So this is just a JavaScript function, and it has this explicit return because we're in JavaScript, and what it's returning is called JSX.
00:12:20 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.
00:12:31 So I have defined this blog container, but I'm not rendering it anywhere. I want to render it into my root node.
00:12:42 My blog container is going to import from 'blog_container', so I'm just going to delete this instead of rendering the generated little tiny component.
00:12:59 I'm going to render my blog container. So at this point, we should see whatever is in the blog container on the page.
00:13:10 Yeah, okay, great! It's still looking bad because of this thing. I'll get rid of this, and now we have a full, I mean, our only view as a React view.
00:13:23 So we're going to just continue to build only in the blog container. What's a blog without posts? It's nothing! So we need to find a way to get some data onto this page.
00:13:39 And the way we're going to do that is by making a request to our GraphQL backend from our client here.
00:13:55 So we need to go back to our GraphQL and set some things up. As I mentioned, the GraphQL installation added this gradual folder and then two folders within: mutations and types. That's where we're going to keep our data.
00:14:10 Alright, we have our definitions of these GraphQL types. If I look here, there's a query type and two mutation types with a bunch of test fields. We could play with those, but I'm going to skip over them for now.
00:14:26 What I need is a new type. These things are working off of default type strings, so this test field is returning some kind of default GraphQL type, a string.
00:14:36 As you can see here, that string is 'Hello, World!' So I need to define a new type, which everything has built off the types of mutations.
00:14:58 Luckily, there is a command for this as well: 'rails generate graphql:object post'. This will create a post with a capital 'P', a title.
00:15:05 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 frontend.
00:15:20 Quite cool! So it made a single file called 'post_type'. You know, I don't look for that. Here it is! It just generated this big thing for me, which is awesome.
00:15:36 And I know that I have a GraphQL type called 'post_type', and it has these fields on it. So, what do I need to do with them?
00:15:49 I need to expose them to the root layer of my API. So the way you do that is you define a field. Whatever I want to call that, I'm going to call it 'posts'.
00:16:01 I want to list posts, so I'm going to say this new type ID is 'post_type', and as part of the DSL, the GraphQL library comes with this 'list' type method.
00:16:13 That will basically return an array of post types, however many I'm going to get in my resolve block.
00:16:29 Let's suppose! The other really cool thing about GraphQL is that it's pretty much self-documenting based on just what I write here.
00:16:45 You know what you're going to get because I just said, 'Okay, I'm going to return a list of posts.' So this is a resolve block; it's a lambda.
00:17:03 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 column that is Post.
00:17:14 All I want is all the posts; I don't care what order they're in. So, there's another really cool thing about GraphQL.
00:17:27 I don't know if I mentioned this yet; I can't remember, but it also initialized with this other route called GraphiQL or GraphQL, however you want to say it.
00:17:38 This is an in-editor IDE for you to test out your queries as you write. So like, the query we just wrote is...
00:17:52 Okay, that's the best kind of feedback! Okay, cool. I hadn't written that yet.
00:18:09 This is a documentation explorer; it's a great name for it, and that's exactly what it is. You see it has the route types here of query and mutation.
00:18:24 So I can click into this and say, 'What do I have available to me in my GraphQL API?' I see posts in our test field, and we can see over here on this root query type that we have these two fields: posts and test.
00:18:35 So, not this - this is a GraphQL query over here. This is exactly what we're going to ask the database for.
00:18:45 So I start typing; it's very, very helpful in that it tells me what I can type.
00:18:52 Basically, like, I could type in 'a', and it will say, 'I go; there's nothing with that.' What do you want, really?
00:19:01 And I think I want titles, so I'm getting some data! There are a couple of blog posts that I seeded.
00:19:14 As I mentioned, two of them are just things that I wrote, while one of them is a real blog post from the Devend blog.
00:19:27 That's great! 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.
00:19:36 If I wanted content as well, I'd have to put content in there explicitly so that the API knows what to get. We could get all three of the things, but I really just see titles.
00:19:47 So, what do we do with this type? What I do is 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.
00:20:01 This is our blog container. It doesn't do anything, and really what we need it to do right now is go make a request to our API.
00:20:16 So I'm going to define a function called 'get_all_posts'. Well, okay! So these functions are available within the component.
00:20:28 They're just functions to this Pod Container component, so 'get_all_posts'. I didn't want to add any more libraries; this is just the basic config.
00:20:39 So we're going to use the fetch API. Here's a nice big snippet for you. The fetch API is just built into React right now, which is great.
00:20:50 You can make any kind of HTTP request with the fetch. You just specify the URL here, the method, we know it's going to be POST.
00:21:02 Headers, and then in the body, this is where you're going to set your GraphQL query so you just kind of give it a key, give it a string, and then I'm going to copy the GraphQL query I was playing with and paste it.
00:21:16 That's what I'm going to do. I'm going to resolve the promises, and veterans of promises yet to resolve it once to JSON and then a new year's all, but again, we'll see what we get in this last part here.
00:21:41 Anyway, where do I want to call the function? I want this data and the fetch request to have been called before the page renders.
00:21:53 So components have these things called lifecycle methods, and we're going to use the 'componentDidMount'. There are a couple of them, and they're totally worth reading about, and they're very helpful.
00:22:03 'componentDidMount', and I'm going to have a componentDidMount called 'get_all_posts'. So this will call before...
00:22:16 Fast! It'll call before the render loads, as you kind of just saw there.
00:22:27 Like, it's just like pops open here, so I'm invited. Bugger, this is too big to even operate in.
00:22:40 What do I have? I have this response data and it's got posts.
00:22:49 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 wanna show in my component.
00:23:01 So what do I do with this data? I've got 'response data posts' that's an array, so I need to have that accessible in the render method.
00:23:14 The way I'm gonna do that is use another built-in React function called state. It's a React property, and Arledge. Sure we want to call this that state.
00:23:25 State is built into every React component as well, so you can hold anything you want in state. I'm gonna hold posts here and just set it as an empty array.
00:23:39 This is like my initialization of the state of the React component. Like, there's nothing there.
00:23:51 I can't just call this 'get_all_posts' here, except I see it works.
00:24:02 So the order in which things are going to work is the component is 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.
00:24:14 'componentDidMount' is going to call next, and it's going to call 'get_all_posts.' This will call our fetch method.
00:24:28 At the very end, we're going to reset the state, reassign that empty array into actually having data, so it'll say posts.
00:24:42 Data posts. So then state is available to every part of the component, so I can do a - oh not the head posts! Equal since that state posts!
00:24:56 So this constant data base, and then I'm gonna just iterate over them in the JSX, so to evaluate any JavaScript, you use double curly braces in JSX.
00:25:09 And we can just use, you know, normally es6 map for a single post and you give it an index.
00:25:38 Alright, so right! It looks like HTML! It's not HTML, it's JSX, so you do curly braces to evaluate at the post title.
00:25:50 Cross your fingers, guys. What do we have? We have... Oh yes! We've got a list of titles!
00:26:03 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!
00:26:13 Okay! What do we want to do? Actually, I want to show the post content as well. So everything's going to be on a single page.
00:26:35 I don't have a router, so we're not going to have like a show page. It's just going to be right there on this single page.
00:26:58 So I'll do this. Okay, great! Adjacent JSX elements must be wrapped in a closing tag.
00:27:07 Learning a little bit about JSX here; that just means that you can't have two siblings right there next to each other. They need to be wrapped in something.
00:27:21 I'm gonna wrap them in a div. You can wrap them in whatever you want, and then that should load properly.
00:27:36 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.
00:27:46 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.
00:28:03 And now we have some content! So that looks like garbage, but there's no styling; there's not going to be in this talk.
00:28:13 So just hold tight, you know, please! There's data!
00:28:28 Ah! Cool! So we are rendering blog posts. I think that's really great.
00:28:41 So you know how to get data from our back-end. Now, we need to learn how to change some data.
00:29:01 So, I know this is called 'CRUD'. We're going to go out of order, and we're going to do the 'D' of CRUD first.
00:29:15 So we're going to delete. Really, when it comes down to it, the other thing about GraphQL is that you only have a mutation and a query.
00:29:31 You don't have CRUD; you don't have gets and posts and puts and patches and those deletes. You only have one thing, so it's not exactly CRUD anymore.
00:29:45 Like, the definition of CRUD is a little different here, but let's do this.
00:29:58 I need a delete link. So I know that the delete link itself is going to make another fetch request.
00:30:09 So just to keep it click-contained, I'm going to create a new component for 'delete_link', called 'DeleteLink', and I'm just going to put the word delete.
00:30:28 I will give it a class, which is, you know, link. Then I'm going to render it. I'm going to render it in the blog container.
00:30:43 Import link. I'm going to render it right below the post title. Let's see!
00:30:56 Oh yeah, okay. So now, each post adds a delete.
00:31:03 It does not look like a link. I'm going to just very quickly change that because that's too crazy, and I'll say links are usually blue.
00:31:15 So the other really cool thing about having a React app in your Rails app is that you get the asset pipeline, which we all know and love!
00:31:30 I like that a lot! So cool, this thing doesn't do anything.
00:31:42 It's a div that's styled to look like a link. What I want to do is give it an onclick handler, so you call a function called 'handle_delete'.
00:31:56 I'll define 'handle_delete' as an actual function again in this component, and we're going to make another fetch request.
00:32:09 So the same thing, the same structure, but now we need to make a different kind of query, essentially.
00:32:20 Here, we need to make a query for mutation, and we don't have any mutations, so we have to go back to GraphQL.
00:32:38 No, I don't see GraphQL mutations. Yeah, the mutations are empty, so I'm going to create a GraphQL mutation.
00:32:53 It's going to be called 'delete_post'. That's just the way it's going to be.
00:33:05 So that added a couple of things here for us. It added a file under mutations, called 'delete_post'.
00:33:16 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.
00:33:30 But it looks kind of similar in a lot of ways, so it's actually really nice.
00:33:41 It also added the field for me on the mutation root type: 'delete_post' has a field now on this mutation type.
00:33:54 Okay, let's see if this thing has directions for me; it says to define your return fields.
00:34:04 So it's suggesting I return a post, but because I'm deleting, I'm actually just going to return a message.
00:34:15 And I'm gonna use the default GraphQL type of a string because I'm just going to say, 'If all goes according to plan, the message is: Post was deleted'.
00:34:30 That's what I want to see somewhere, probably in a flash message eventually, but maybe just in my console for now.
00:34:46 The next thing I'm going to do is define arguments: input, field name, type: string. This also doesn't feel quite right.
00:35:03 Because when we delete, we usually delete by finding links: The ID and then deleting the object that we found.
00:35:17 So the input field is going to be an ID, and again we can use the generic GraphQL types of ID.
00:35:26 And to do the resolve function, we can just do some Active Record stuff. Let's find the ID.
00:35:36 Which I'm going to pass through in the args, kind of like how we saw in the query before, and I will just destroy that post. No questions!
00:35:52 I spelled it wrong just now. Cool, destroy happens to me all the time!
00:36:06 Yeah, so we're just gonna assume that works! I'm not gonna... I'm gonna put today.
00:36:18 So, let's see if we can use GraphiQL to test that out again.
00:36:30 If I refresh this page, look at our new mutations! We have a single field for delete post, and it takes input.
00:36:45 So I think the same way that I created the query over here, I can do the same thing.
00:36:59 I can start typing delete post input and then put type is ID, right?
00:37:08 So I'm gonna delete the first one. Let's see.
00:37:20 Okay, so I just had a guess there; I assumed there was a post with the ID of one, but it does say that the post was deleted.
00:37:34 So if we go back to our front end and refresh, there are only two, which is exactly what I wanted!
00:37:49 Cool! So I'm gonna do the same thing where I copy this mutation, put it into the delete link query.
00:38:10 So, like, somehow I need to get the post ID. The way I'm going to do that is if I go back to the blog container.
00:38:24 We're iterating through these posts, right? So this is like a post row, and the div itself is contained to a specific post.
00:38:36 So I can send in a property called post ID, which would be post dot ID.
00:38:48 This isn't going to work immediately because I'm not requesting the ID. So if I want to do that, I have to put it here.
00:39:02 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.
00:39:14 So the delete link can access these properties via a call that looks like this: this.props.postID.
00:39:28 So, that's how you can pass data from your parent down to your child, and that's a very common pattern in React.
00:39:43 Let's see where we're at. I hope that hit delete.
00:39:54 Yes! Okay, so that thing is deleted out of the database.
00:40:04 And I'm gonna do a couple more because there are too many. Awesome!
00:40:17 Got still leading! We have... I'm shocked because I still have time.
00:40:28 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!
00:40:41 Let's see... I guess we should just keep going. We may as well do create.
00:40:56 Oh, I don't know! That sounds kind of ambitious. Let's try it.
00:41:11 Let's see if we can check out. Everything on here is going to be in a branch.
00:41:23 Eventually, I'm sorry~ not a branch, a Git repo! And everything is branched out pretty precisely.
00:41:36 So if you wanted to check out different spots of the tutorial, that will be available, you could start from wherever you wanted.
00:41:48 They build on each other, so like in this tutorial, it's gonna go see first C of CRUD, R of CRUD, C of CRUD, and so on.
00:42:00 Let's just see what it looks like completed. I know; let's refresh.
00:42:11 That's what they all say! Let's go through all the branches.
00:42:22 Okay, so here I did add a form. This form lives in its own component.
00:42:36 So again, it's just a little component. It has some state for title and content.
00:42:47 This is like exactly how the docs of React tell you to make a form.
00:43:00 There is plenty of information about like why this is how it's set up, but forms, again, look a lot like HTML.
00:43:13 But they have all of these handlers and properties that help set the states and make changes and submit data.
00:43:26 So these inputs, this onchange, or claims handled in change and handle input change; it's just resetting the state.
00:43:38 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's here.
00:43:49 So like, oh! Right! Okay! So nothing's happening because we don't have a create mutation. So let's see...
00:44:02 Oh yeah we do! I forgot! Okay!
00:44:15 I have already created my create mutation. Let's just go look at it: 'create_post'.
00:44:30 So I did this the same way I made my 'delete_post', which was 'rails g graphql:mutation create_post'.
00:44:42 This one you can see has a return field for the post type, unlike delete, which returned a message.
00:44:56 I think that's what I did. This one has an input field for title and content, and here the resolve block, again, Active Record, whatever you want to do.
00:45:06 We're gonna create a post, so we create a post with the title and content that comes through in the arguments.
00:45:20 I am, and actually... Oops! There's a bolt to us here!
00:45:33 This fetch has a mutation called 'create_post'. These all start to look a lot alike if you can't tell already.
00:45:48 Let's see, let's check out!
00:46:00 It's in execution still!
00:46:10 This might be the end of it; this might just be like everything working.
00:46:22 So, we have this delete; can delete things! And I can edit!
00:46:35 So the way I chose to edit for the sake of this demo was to do it on the same page.
00:46:48 Right? Like I said, I don't have a router, I don't want to have a page just to view and edit forms.
00:47:04 So you can edit, and oh, tips for petting every dog on the street or something? Like, I wrote that!
00:47:17 You can edit this to just be like, 'Whew!' That says 'phew', but you know I do mean 'woo!'
00:47:29 Then it edits in place. This is more or less the completed CRUD application that I meant to demonstrate today.
00:47:38 And that's it, actually! So thank you so much for coming, guys! I had a blast; hope you did too!