Ancient City Ruby -- Talk Repo -- Jamon Holmgren / Morgan Laco
This is the repo for the live coding talk by Jamon Holmgren and Morgan Laco.
./AcrRails
foldermaster
branchgem "graphql"
to the Gemfile if it's not already therebundle install
yarn
rails g graphql:install
rails g scaffold Post title:string body:string
rails db:migrate
rails g graphql:object Post id:ID title:String body:String
graphql/types/query_type.rb
:module Types
class QueryType < Types::BaseObject
field :posts, [PostType], null: true do
description "Find all posts"
end
def posts
Post.all
end
end
end
rails server
{
posts {
id
title
body
}
}
rails g task graphql dump
lib/tasks/graphql.rake
:namespace :graphql do
desc "Dump GraphQL Schema File"
task dump: :environment do
schema_dump = AcrRailsSchema.to_definition
schema_path = Rails.root.join("./acr.graphql")
File.write(schema_path, schema_dump)
puts schema_path
end
end
rake graphql:dump
app/controllers/graphql_controller.rb
file to remove the CSRF protection so we can use it as an API:class GraphqlController < ApplicationController
protect_from_forgery with: :null_session
# ...
end
AcrReactNative
directory.yarn
and cd ios; pod install; cd -
yarn add [email protected] [email protected] [email protected]
yarn mst-gql --format ts ../AcrRails/acr.graphql --outDir=app/models/gql
app/models/root-store/root-store.ts
:// .. omitted above
import { RootStoreBase } from "../gql/RootStore.base"
/**
* A RootStore model.
*/
export const RootStoreModel = RootStoreBase.props({
navigationStore: types.optional(NavigationStoreModel, {}),
})
// .. omitted below
app/models/environment.ts
, remove anything to do with the API, and in the constructor, point to the running localhost server:import { Reactotron } from "../services/reactotron"
import { createHttpClient } from "mst-gql"
import { GraphQLClient } from "graphql-request"
export class Environment {
reactotron: Reactotron
gqlHttpClient: GraphQLClient
constructor() {
this.reactotron = new Reactotron()
this.gqlHttpClient = createHttpClient("http://localhost:3000/graphql")
}
async setup() {
await this.reactotron.setup()
}
}
app/models/root-store/root-store-context.ts
:import { createStoreContext, createUseQueryHook } from "mst-gql"
import React from "react"
export const RootStoreContext = createStoreContext<RootStore>(React)
export const useQuery = createUseQueryHook(RootStoreContext, React)
app/screens/welcome-screen/welcome-screen.tsx
to show the posts:// ...
import { useStores, useQuery } from "../../models/root-store"
// ...
export const WelcomeScreen: React.FunctionComponent<WelcomeScreenProps> = observer(props => {
const rootStore = useStores()
const { query } = useQuery(store => store.queryPosts())
// ... in the JSX portion:
<View>
{Array.from(rootStore.posts).map(([k, p]) => (
<Text key={k} style={CONTENT}>{p.title}</Text>
))}
</View>
// ... and update the continue button to allow refreshing:
<SafeAreaView style={FOOTER}>
<Button style={CONTINUE} textStyle={CONTINUE_TEXT} text="Refresh" onPress={query.refetch} />
</SafeAreaView>
rails g graphql:mutation DeletePost
app/graphql/mutations/delete_post.rb
:module Mutations
class DeletePost < GraphQL::Schema::RelayClassicMutation
graphql_name "DeletePost"
field :post, Types::PostType, null: true
field :result, Boolean, null: true
argument :id, ID, required: true
def resolve(**args)
post = Post.find(args[:id])
post.destroy
{
post: post,
result: post.errors.blank?,
}
end
end
end
rake graphql:dump
yarn mst-gql --format ts ../AcrRails/acr.graphql --outDir=app/models/gql
app/models/root-store/root-store.ts
to add the deletePost
action:export const RootStoreModel = RootStoreBase.props({
navigationStore: types.optional(NavigationStoreModel, {}),
}).actions(self => ({
deletePost(id: string) {
return self.mutateDeletePost({ input: { id } }, undefined, () => self.posts.delete(id))
},
}))
app/screens/welcome-screen/welcome-screen.tsx
file:// just above the JSX
const { setQuery } = useQuery()
// in the JSX, modify this section
return (
<View style={FULL}>
<Wallpaper />
<Screen style={CONTAINER} preset="scroll" backgroundColor={color.transparent}>
<View>
{Array.from(rootStore.posts).map(([k, p]) => (
<View key={k} style={{ flexDirection: "row", alignItems: "center" }}>
<Text style={{ fontSize: 23 }}>{p.title}</Text>
<TouchableOpacity onPress={()=> setQuery(rootStore.deletePost(p.id))}>
<Text style={{ fontSize: 16 }}> - Delete</Text>
</TouchableOpacity>
</View>
))}
</View>
</Screen>
<SafeAreaView style={FOOTER}>
<Button style={CONTINUE} textStyle={CONTINUE_TEXT} text="Refresh" onPress={query.refetch} />
</SafeAreaView>
</View>
)
rails db:reset
rm ./db/schema.rb
master
or:rails d scaffold Post
rails d graphql:object Post