forked from FusionAuth/fusionauth-site
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add RemoteCode component. quickstarts collection. rails quickstart
- Loading branch information
Showing
9 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
--- | ||
/** | ||
* Remote code fetcher and syntax highlighter via the Astro Code component. | ||
*/ | ||
export interface Props { | ||
/** | ||
* Url to fetch code from. Also allows selecting specific line(s) of code with | ||
* the Github line syntax. | ||
* E.g., https://raw.githubusercontent.com/FusionAuth/fusionauth-example-client-libraries/main/ruby/Gemfile#L3 | ||
*/ | ||
url: string; | ||
/** | ||
* The language of your code. | ||
* Supports all languages listed here: https://github.com/shikijs/shiki/blob/main/docs/languages.md#all-languages | ||
* | ||
* @default "plaintext" | ||
*/ | ||
lang?: string; | ||
/** | ||
* Optional tags marking beginning and end of content to include | ||
* Loosely based on https://docs.asciidoctor.org/asciidoc/latest/directives/include-tagged-regions/ | ||
* Note: Currently only supports one set of tags. | ||
*/ | ||
tags?: string; | ||
} | ||
const { url, lang = 'plaintext', tags} = Astro.props as Props; | ||
import { Code } from 'astro/components'; | ||
const remoteResponse = await fetch(url); | ||
const remoteCode = await remoteResponse.text(); | ||
let remoteSelectedCode; | ||
if (tags) { | ||
remoteSelectedCode = selectTagged(remoteCode, tags); | ||
} else { | ||
const matchLines = url.match(/.*#L(\d+)(-L(\d+))?$/); | ||
if (matchLines) { | ||
remoteSelectedCode = selectLines(remoteCode, matchLines[1], matchLines[3]); | ||
} else { | ||
remoteSelectedCode = remoteCode.trim(); | ||
} | ||
} | ||
function selectTagged(content: string, tags: string): string { | ||
const lines = remoteCode.split("\n"); | ||
const startLine = lines.findIndex((line) => line.includes(`tag::${tags}`)); | ||
const endLine = lines.findIndex((line) => line.includes(`end::${tags}`)); | ||
return lines.slice(startLine + 1, endLine).join("\n"); | ||
} | ||
function selectLines(content: string, lineNum: string, lineEnd: string): string { | ||
const lines = content.split("\n"); | ||
if (lineNum && lineEnd) { | ||
return lines.slice(lineNum-1, lineEnd-1).join("\n"); | ||
} else if (lineNum) { | ||
return lines[lineNum - 1]; | ||
} else { | ||
return content; | ||
} | ||
} | ||
--- | ||
<Code code={remoteSelectedCode} lang={lang}/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
import ClickableCard from "../ClickableCard.astro"; | ||
import { getCollection } from "astro:content"; | ||
const { section } = Astro.props; | ||
const tools = await getCollection("quickstarts"); | ||
--- | ||
|
||
<div class="gap-6 grid grid-cols-1 not-prose lg:grid-cols-2" xmlns="http://www.w3.org/1999/xhtml"> | ||
{tools.map(tool => | ||
<ClickableCard href={`/quickstarts/${tool.slug}`} title={tool.data.title} description={tool.data.description} icon={tool.data.icon ? tool.data.icon : null}/> | ||
)} | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
title: Quickstarts | ||
description: Enjoy these web based developer tools that our team has put together. | ||
disableTOC: true | ||
section: web | ||
--- | ||
import Index from "../../components/quickstarts/Index.astro"; | ||
|
||
<Index/> |
195 changes: 195 additions & 0 deletions
195
astro/src/content/quickstarts/quickstart-ruby-rails-web.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
--- | ||
title: Quickstart Ruby on Rails and FusionAuth | ||
description: Quickstart integration of Ruby on Rails web application with FusionAuth | ||
navcategory: getting-started | ||
prerequisites: Ruby, bundler and Rails | ||
section: web | ||
technology: Ruby on Rails | ||
language: Ruby | ||
--- | ||
import RemoteCode from '/src/components/RemoteCode.astro'; | ||
|
||
In this tutorial, you are going to learn how to integrate a Ruby on Rails application with FusionAuth. | ||
The docker compose file and source code for a complete application are available at | ||
https://github.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web | ||
|
||
## Prerequisites | ||
|
||
- [Ruby](https://www.ruby-lang.org/en/documentation/installation/): This will be needed for pulling down the various dependencies. | ||
- [Rails](https://guides.rubyonrails.org/getting_started.html): This will be used in order to run the Rails server. | ||
- [Docker](https://www.docker.com): The quickest way to stand up FusionAuth. | ||
- (Alternatively, you can [Install FusionAuth Manually](https://fusionauth.io/docs/v1/tech/installation-guide/)). | ||
|
||
This app has been tested with Ruby 3.2.2 and Rails 7.0.4.3 | ||
|
||
## FusionAuth Installation via Docker | ||
|
||
The root of this project directory (next to this README) are two files [a Docker compose file](./docker-compose.yml) and an [environment variables configuration file](./.env). Assuming you have Docker installed on your machine, you can stand up FusionAuth up on your machine with: | ||
|
||
``` | ||
git clone https://github.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web.git | ||
cd fusionauth-quickstart-ruby-on-rails-web | ||
docker-compose up -d | ||
``` | ||
|
||
The FusionAuth configuration files also make use of a unique feature of FusionAuth, called [Kickstart](https://fusionauth.io/docs/v1/tech/installation-guide/kickstart): when FusionAuth comes up for the first time, it will look at the [Kickstart file](./kickstart/kickstart.json) and mimic API calls to configure FusionAuth for use when it is first run. | ||
|
||
> **NOTE**: If you ever want to reset the FusionAuth system, delete the volumes created by docker-compose by executing `docker-compose down -v`. | ||
FusionAuth will be initially configured with these settings: | ||
|
||
* Your client Id is: `e9fdb985-9173-4e01-9d73-ac2d60d1dc8e` | ||
* Your client secret is: `super-secret-secret-that-should-be-regenerated-for-production` | ||
* Your example username is `richard@example.com` and your password is `password`. | ||
* Your admin username is `admin@example.com` and your password is `password`. | ||
* Your fusionAuthBaseUrl is 'http://localhost:9011/' | ||
|
||
You can log into the [FusionAuth admin UI](http://localhost:9011/admin) and look around if you want, but with Docker/Kickstart you don't need to. | ||
|
||
## Create your Ruby on Rails Application | ||
|
||
Now you are going to create a Ruby on Rails application. While this section builds a | ||
simple Ruby on Rails application, you can use the same configuration to | ||
integrate your existing Ruby on Rails application with FusionAuth. | ||
|
||
```bash | ||
rails new myapp && cd myapp | ||
``` | ||
|
||
### Configure Omniauth | ||
|
||
Install the omniauth gem and other supporting gems. Add the following three lines to your `Gemfile`. | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/Gemfile" | ||
lang="ruby" | ||
tags="gemfile"/> | ||
|
||
Then, install them. | ||
|
||
```bash | ||
bundle install | ||
``` | ||
|
||
Next, update your `config/environments/development.rb` file with FusionAuth OpenID Connect (OIDC) environment specific configuration information. | ||
|
||
> **NOTE**: You'll have to add similar configuration to the relevant environment files when deploying to prod or other environments. | ||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/config/environments/development.rb" | ||
lang="ruby" | ||
tags="oidcConfig"/> | ||
|
||
Configure Omniauth by creating `config/initializers/omniauth.rb` with the following | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/config/initializers/omniauth.rb" | ||
lang="ruby" /> | ||
|
||
This pulls from the environment file and configures omniauth to communicate with FusionAuth. | ||
|
||
### Add Controllers | ||
|
||
Next, you can create some controllers with the following shell commands: | ||
|
||
```shell | ||
rails generate controller auth | ||
rails generate controller home | ||
rails generate controller make_change | ||
``` | ||
|
||
These controllers have the following purposes: | ||
|
||
* `auth` is for omniauth integration | ||
* `home` is an unprotected home page with a login button | ||
* `make_change` is a protected page for our example bank application | ||
|
||
First, let's update the `config/routes.rb` file. Here's what that should look like: | ||
|
||
<RemoteCode url=" | ||
https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/config/routes.rb" | ||
lang="ruby" /> | ||
|
||
Some simple routes corresponding to the controllers: | ||
|
||
* `make_change` is the protected bank page | ||
* `home` is the home page, which is available to unauthenticated users. This is also the default page. | ||
* `logout` is tied to the auth controller's logout method. | ||
* `auth/:provider/callback` is the omniauth callback method, which completes the OpenID Connect (OIDC) grant. | ||
|
||
Now, update the auth controller at `app/controllers/auth_controller.rb` to look like this, which fulfills some of the routes above. | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/controllers/auth_controller.rb" | ||
lang="ruby" /> | ||
|
||
This lets us have a nice `logout` method and also handle the callback from omniauth. The latter sets a `session` attribute with user data, which can be used by views later. | ||
|
||
Now, update the application controller at `app/controllers/application_controller.rb`. | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/controllers/application_controller.rb" | ||
lang="ruby" /> | ||
|
||
- `authenticate_user!` enforces authentication for all routes in your application by checking for the session attribute set by the auth controller after a successful login. | ||
- `redirect_non_localhost!` ensures users access the web app via `localhost` instead of a url like http:127.0.0.1:3000/ . FusionAuth's origin and redirect URL configurations in this example expect `localhost`. In production, similar logic should be updated with your domain name. | ||
|
||
Now, let's build out the home page. Update the home controller at `app/controllers/home_controller.rb` to look like this: | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/controllers/home_controller.rb" | ||
lang="ruby" /> | ||
|
||
You're skipping authentication for this route. This is so that a user has someplace to go if they are unauthenticated. | ||
|
||
### Add Views | ||
|
||
The view is also welcoming, but prompts them to login. Otherwise, it shows a mock account balance. Replace `app/views/home/index.html.erb` with this: | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/views/home/index.html.erb" | ||
lang="ruby" /> | ||
|
||
Finally, update the layout so the user has login or logout buttons on every page. Add the below code to `app/views/layouts/application.html.erb` just after the `<body>` tag. | ||
|
||
<RemoteCode url="https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/views/layouts/application.html.erb" | ||
lang="ruby" | ||
tags="applicationLayout"/> | ||
|
||
### Add Styling | ||
|
||
Now, add some image assets and styling to make this look like a real application with the following shell commands: | ||
|
||
```shell | ||
wget -o app/assets/images/example_bank_logo.svg https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/assets/images/example_bank_logo.svg | ||
wget -o app/assets/images/fusion_auth_logo.svg https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/assets/images/fusion_auth_logo.svg | ||
wget -o app/assets/images/money.jpg https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/assets/images/money.jpg | ||
wget -o app/assets/stylesheets/changebank.css https://raw.githubusercontent.com/FusionAuth/fusionauth-quickstart-ruby-on-rails-web/main/complete-app/app/assets/stylesheets/changebank.css | ||
``` | ||
|
||
Once you’ve created these files, you can test the application. | ||
|
||
## Run the App | ||
|
||
Start up the Rails application using this command: | ||
|
||
```shell | ||
OP_SECRET_KEY="super-secret-secret-that-should-be-regenerated-for-production" bundle exec rails s | ||
``` | ||
|
||
`OP_SECRET_KEY` is the client secret, which was defined by the [FusionAuth Installation via Docker](#fusionauth-installation-via-docker) step. You don't want to commit secrets like this to version control, so use an environment variable. | ||
|
||
You can now open up an incognito window and visit the Rails app at http://localhost:3000 . | ||
Log in with the user account you created when setting up FusionAuth, and you’ll see the email of the user next to a logout button. | ||
|
||
## Troubleshooting | ||
|
||
* I get `This site can’t be reached localhost refused to connect.` when I click the Login button | ||
|
||
Ensure FusionAuth is running in the Docker container. You should be able to login as the admin user, `admin@example.com` with the password of `password` at http://localhost:9011/admin | ||
|
||
* I get an error page when I click on the Login button with message of `"error_reason" : "invalid_client_id"` | ||
|
||
Ensure the value for `config.x.fusionauth.client_id` in the file `config/environments/development.rb` matches client id configured in FusionAuth for the Example App application at http://localhost:9011/admin/application/ | ||
|
||
* I'm getting an error from Rails after logging in | ||
|
||
``` | ||
Rack::OAuth2::Client::Error | ||
invalid_client :: Invalid client authentication credentials. | ||
``` | ||
|
||
This indicates that Omniauth is unable to call FusionAuth to validate the returned token. It is likely caused my not supplying the correct *client secret*. Ensure the `OP_SECRET_KEY` used to start rails matches the FusionAuth ExampleApp client secret. http://localhost:9011/admin/application/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
import { getCollection } from "astro:content"; | ||
import Default from "./Default.astro"; | ||
const quickstarts = await getCollection("quickstarts"); | ||
const sections = []; | ||
for (const quickstart of quickstarts) { | ||
if (quickstart.id.indexOf("index.md") !== -1) { | ||
continue; | ||
} | ||
sections.push( | ||
{ | ||
"title": quickstart.data.title, | ||
"path": `/quickstarts/${quickstart.slug}`, | ||
"icon": quickstart.data.icon, | ||
"color": quickstart.data.color | ||
} | ||
) | ||
} | ||
--- | ||
<Default sections={sections} sideMenu={[]} {...Astro.props}> | ||
<slot/> | ||
</Default> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
import { getCollection } from "astro:content"; | ||
import Layout from "../../layouts/Quickstart.astro"; | ||
export async function getStaticPaths() { | ||
const entry = await getCollection("quickstarts"); | ||
return entry.map(entry => ({ | ||
params: { slug: entry.slug }, props: { entry }, | ||
})); | ||
} | ||
const { entry } = Astro.props; | ||
const { Content, headings } = await entry.render(); | ||
--- | ||
<Layout frontmatter={entry.data} headings={headings}> | ||
<Content/> | ||
</Layout> |
Oops, something went wrong.