class RepositoriesController < ApplicationController # Define query for repository listing. # # All queries MUST be assigned to constants and therefore be statically # defined. Queries MUST NOT be generated at request time. IndexQuery = GitHub::Client.parse <<-'GRAPHQL' # All read requests are defined in a "query" operation query { # viewer is the currently authenticated User viewer { # "...FooConstant" is the fragment spread syntax to include the index # view's fragment. # # "Views::Repositories::Index::Viewer" means the fragment is defined # in app/views/repositories/index.html.erb and named Viewer. ...Views::Repositories::Index::Viewer } } GRAPHQL # GET /repositories def index # Use query helper defined in ApplicationController to execute the query. # `query` returns a GraphQL::Client::QueryResult instance with accessors # that map to the query structure. data = query IndexQuery # Render the app/views/repositories/index.html.erb template with our # current User. # # Using explicit render calls with locals is preferred to implicit render # with instance variables. render "repositories/index", locals: { viewer: data.viewer } end # Define query for "Show more repositories..." AJAX action. MoreQuery = GitHub::Client.parse <<-'GRAPHQL' # This query uses variables to accept an "after" param to load the next # 10 repositories. query($after: String!) { viewer { repositories(first: 10, after: $after) { # Instead of refetching all of the index page's data, we only need # the data for the repositories container partial. ...Views::Repositories::Repositories::RepositoryConnection } } } GRAPHQL # GET /repositories/more?after=CURSOR def more # Execute the MoreQuery passing along data from params to the query. data = query MoreQuery, after: params[:after] # Using an explicit render again, just render the repositories list partial # and return it to the client. render partial: "repositories/repositories", locals: { repositories: data.viewer.repositories } end # Define query for repository show page. ShowQuery = GitHub::Client.parse <<-'GRAPHQL' # Query is parameterized by a $id variable. query($id: ID!) { # Use global id Node lookup node(id: $id) { # Include fragment for app/views/repositories/show.html.erb ...Views::Repositories::Show::Repository } } GRAPHQL # GET /repositories/ID def show # Though we've only defined part of the ShowQuery in the controller, when # query(ShowQuery) is executed, we're sending along the query as well as # all of its fragment dependencies to the API server. # # Here's the raw query that's actually being sent. # # query RepositoriesController__ShowQuery($id: ID!) { # node(id: $id) { # ...Views__Repositories__Show__Repository # } # } # # fragment Views__Repositories__Show__Repository on Repository { # id # owner { # login # } # name # description # homepageUrl # ...Views__Repositories__Navigation__Repository # } # # fragment Views__Repositories__Navigation__Repository on Repository { # hasIssuesEnabled # } data = query ShowQuery, id: params[:id] if repository = data.node render "repositories/show", locals: { repository: repository } else # If node can't be found, 404. This may happen if the repository doesn't # exist, we don't have permission or we used a global ID that was the # wrong type. head :not_found end end StarMutation = GitHub::Client.parse <<-'GRAPHQL' mutation($id: ID!) { star(input: { starrableId: $id }) { starrable { ...Views::Repositories::Star::Repository } } } GRAPHQL def star data = query StarMutation, id: params[:id] if repository = data.star respond_to do |format| format.js { render partial: "repositories/star", locals: { repository: data.star.starrable } } format.html { redirect_to "/repositories" } end else head :not_found end end UnstarMutation = GitHub::Client.parse <<-'GRAPHQL' mutation($id: ID!) { unstar(input: { starrableId: $id }) { starrable { ...Views::Repositories::Star::Repository } } } GRAPHQL def unstar data = query UnstarMutation, id: params[:id] if repository = data.unstar respond_to do |format| format.js { render partial: "repositories/star", locals: { repository: data.unstar.starrable } } format.html { redirect_to "/repositories" } end else head :not_found end end end