Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.2] Clean up Web app guide #244

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
37 changes: 25 additions & 12 deletions content/v2.2/introduction/building-a-web-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ We can find this view's template in our `app` directory at `app/templates/home/s
<h1>Welcome to Bookshelf</h1>
```

At this point we need to compile our frontend assets just once, so they're available to the layout in `app/views/layouts/app.html.erb`:
At this point we need to compile our frontend assets (a favicon, some very simple CSS, and placeholder JS) just once, so they're available to the layout in `app/views/layouts/app.html.erb`:

```shell
$ bundle exec hanami assets compile
Expand Down Expand Up @@ -365,7 +365,7 @@ $ bundle exec hanami generate relation books
This creates the following file at `app/relations/books.rb`:

```ruby
# lib/bookshelf/persistence/relations/books.rb
# lib/bookshelf/relations/books.rb

module Bookshelf
module Relations
Expand All @@ -376,10 +376,13 @@ module Bookshelf
end
```

Lastly, we need to ensure the database is cleaned between tests. Add the Database Cleaner gem to your `Gemfile`:
This tells the relation to use the `'books'` table we just created, and use that table's schema as its own (instead of manually specifying it).

Lastly, we need to ensure the database is cleaned between tests. Add the Database Cleaner gem to the `:test` section of your `Gemfile`:

```ruby
group :test do
# ...
gem "database_cleaner-sequel"
end
```
Expand Down Expand Up @@ -409,7 +412,7 @@ RSpec.configure do |config|
DatabaseCleaner.clean_with(:truncation)
end

config.around(:each, type: :db) do |example|
config.around(:each, type: :feature) do |example|
DatabaseCleaner.cleaning do
example.run
end
Expand Down Expand Up @@ -469,7 +472,9 @@ module Bookshelf
end
```

To access this book repo from the view, we can use Hanami's Deps mixin. Covered in detail in the [container and components](/v2.2/app/container-and-components/) section of the Architecture guide, the Deps mixin gives each of your app's components easy access to the other components it depends on to achieve its work. We'll see this in more detail as these guides progress.
This selects all the attributes from the `books` relation (by default), `order`s them alphabetically by title, and then, finally _materializes_ the query with `#to_a`. This executes the query against the database and then automatically turns each row into a simple object (of class `ROM::Struct`) and puts those into an array.

To access this book repo from the view, we use Hanami's `Deps` mixin, which is how Hanami files declare their dependencies on other files. Covered in detail in the [container and components](/v2.2/app/container-and-components/) section of the Architecture guide, the `Deps` mixin gives each of your app's components easy access to the other components it depends on to achieve its work. We'll see this in more detail as these guides progress.

For now however, it's enough to know that we can use `include Deps["repos.book_repo"]` to make the repo available via a `book_repo` method within our view.

Expand Down Expand Up @@ -502,7 +507,7 @@ Then we can update our template to include the author:

<ul>
<% books.each do |book| %>
<li><%= book[:title] %>, by <%= book[:author] %></li>
<li><%= book.title %>, by <%= book.author %></li>
<% end %>
</ul>
```
Expand Down Expand Up @@ -696,9 +701,11 @@ Failures:
We can use Hanami's action generator to create both a route and an action. Run:

```shell
$ bundle exec hanami generate action books.show
$ bundle exec hanami generate action books.show --skip-tests
```

(We skip creating a spec file for this action because we have the feature spec already. We recommend writing them for your real apps.)

If you inspect `config/routes.rb` you will see the generator has automatically added a new `get "/books/:id", to: "books.show"` route:

```ruby
Expand Down Expand Up @@ -739,6 +746,8 @@ To fetch a single book from our database, we can add a new method to our book re
module Bookshelf
module Repos
class BookRepo < Bookshelf::Repo
# ...

def get(id)
books.by_pk(id).one
end
Expand All @@ -747,6 +756,8 @@ module Bookshelf
end
```

Now, we're calling the `#by_pk` (primary key) method on the books relation, then the `#one` method is the one that _materializes_ the query by executing it and turning into an object.

Then we can edit the view at `app/views/books/show.rb` to get the book via the repo and expose it to the template:

```ruby
Expand All @@ -772,9 +783,9 @@ Lastly, we can populate the template.
```sql
<!-- app/views/books/show.html.erb -->

<h1><%= book[:title] %></h1>
<h1><%= book.title %></h1>

<p>By <%= book[:author] %></p>
<p>By <%= book.author %></p>
```

With this, our happy path test passes, but the test for our 404 now fails:
Expand Down Expand Up @@ -1104,14 +1115,16 @@ To complete our create action, we can add a method to our book repo to create ne
module Bookshelf
module Repos
class BookRepo < Bookshelf::Repo
def create(attributes)
books.changeset(:create, attributes).commit
end
commands :create

# ...
end
end
end
```

Commands are built-in features for repos that you can opt-into. In this case, it defines a `def create(attributes)` method that we can call.

In the action, we can then create this book if the posted params are valid, then setting flash messages and redirecting as required:

```ruby
Expand Down
37 changes: 20 additions & 17 deletions content/v2.2/introduction/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Ideally, you already have some familiarity with web apps and the [Ruby language]

### Prerequisites

To create a Hanami app, you will need Ruby 3.0 or greater. Check your ruby version:
To create a Hanami app, you will need Ruby 3.1 or greater. Check your ruby version:

```shell
$ ruby --version
Expand Down Expand Up @@ -104,6 +104,7 @@ $ tree --gitignore .
│   ├── routes.rb
│   └── settings.rb
├── config.ru
├── db
├── lib
│   ├── bookshelf
│   │   └── types.rb
Expand All @@ -116,27 +117,29 @@ $ tree --gitignore .
├── spec_helper.rb
└── support
├── features.rb
├── operations.rb
├── requests.rb
└── rspec.rb

23 directories, 32 files
25 directories, 33 files
```

Here's how these files and directories are used:

| Location | Purpose |
|---------------------------------|--------------------------------------------|
| Gemfile | The app's gem dependencies, installed using bundler. |
| Guardfile | Supports code reloading in development. |
| Procfile.dev | For running Hanami dev server processes: both the server and assets watcher. |
| package.json | The app's Node.js package dependencies, for assets management, installed using npm. |
| README.md | The app's README document. |
| Rakefile | Support for running Rake tasks. |
| app/ | This is the directory where you'll put the majority of your app's code. |
| config/ | A directory for your app and assets configuration, also including things like routes, settings and Puma configuration. |
| config.ru | The Rack config file. |
| lib/ | A directory for supporting code. |
| spec/ | The app's RSpec test suite. |
| Location | Purpose |
|---------------|----------|
| Gemfile | The app's gem dependencies, installed using bundler. |
| Guardfile | Supports code reloading in development. |
| Procfile.dev | For running Hanami dev server processes: both the server and assets watcher. |
| package.json | The app's Node.js package dependencies, for assets management, installed using npm. |
| README.md | The app's README document. |
| Rakefile | Support for running Rake tasks. |
| app/ | This is the directory where you'll put the majority of your app's code. |
| config/ | A directory for configurations of all kinds. |
| config.ru | The Rack config file. |
| db/ | Where our sqlite database files lives. |
| lib/ | A directory for supporting code. |
| spec/ | The app's RSpec test suite. |

We'll see this structure in more detail as this guide progresses.

Expand All @@ -152,9 +155,9 @@ If all has gone well, you should see output similar to:
08:14:33 web.1 | started with pid 56242
08:14:33 assets.1 | started with pid 56243
08:14:34 assets.1 | [gsg_app] [watch] build finished, watching for changes...
08:14:34 web.1 | 08:14:34 - INFO - Using Guardfile at /Users/tim/Source/scratch/gsg_app/Guardfile.
08:14:34 web.1 | 08:14:34 - INFO - Using Guardfile at ~/bookshelf/Guardfile.
08:14:34 web.1 | 08:14:34 - INFO - Puma starting on port 2300 in development environment.
08:14:34 web.1 | 08:14:34 - INFO - Guard is now watching at '/Users/tim/Source/scratch/gsg_app'
08:14:34 web.1 | 08:14:34 - INFO - Guard is now watching at '~/bookshelf'
08:14:35 web.1 | Puma starting in single mode...
08:14:35 web.1 | * Puma version: 6.4.2 (ruby 3.3.0-p0) ("The Eagle of Durango")
08:14:35 web.1 | * Min threads: 5
Expand Down
Binary file modified content/v2.2/introduction/hanami-welcome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.