Skip to content
Permalink
Browse files

Merge pull request #25 from tomkadwill/action_fixes

Fixed typos and sentence structure
  • Loading branch information...
jodosha committed Jun 16, 2015
2 parents 7463028 + 89ff023 commit bb94aa229eae16f76193b21d6e5351fd9c25b86a
@@ -47,9 +47,9 @@ end

### Action Middleware

Sometimes we need a middleware only for a set of well known resources.
If we mount it at the global or application level, the performance start to degrade.
Actions allow to mount fine grained middleware stack.
Sometimes we need a middleware for a set of well known resources, only.
If we mount it at the global or application level, the performance will start to degrade.
Actions allow us to mount a fine grained middleware stack.

```ruby
# apps/web/controllers/sessions/create.rb
@@ -5,7 +5,7 @@ title: Lotus - Guides - Request & Response
# Request

In order to access the metadata coming from a HTTP request, an action has a private object `request` that derives from `Rack::Request`.
Here an example of a few informations that we can introspect.
Here an example of some information that we can introspect.

```ruby
# apps/web/controllers/dashboard/index.rb
@@ -28,8 +28,8 @@ end
```

<p class="warning">
To instantiate a <code>request</code> for each incoming HTTP request can lead to a minor perf degradation.
As an alternative, please consider to get the same information from private action methods like <code>accepts?</code> or from the raw Rack environment <code>params.env</code>.
Instantiating a <code>request</code> for each incoming HTTP request can lead to minor performance degradation.
As an alternative, please consider getting the same information from private action methods like <code>accepts?</code> or from the raw Rack environment <code>params.env</code>.
</p>

# Response
@@ -25,7 +25,7 @@ The first argument is the name of the adapter for the session storage.
The default value is `:cookie`, that uses `Rack::Session::Cookie`.

<p class="convention">
The name of the session adapter is underscored version of the class name under <code>Rack::Session</code> namespace.
The name of the session adapter is the underscored version of the class name under <code>Rack::Session</code> namespace.
Example: <code>:cookie</code> for <code>Rack::Session::Cookie</code>.
</p>

@@ -34,7 +34,7 @@ Let's say we want to use Redis. We should bundle `redis-rack` and specify the na
Lotus is able to autoload the adapter and use it when the application is started.

<p class="convention">
Custom storages are autoloaded via <code>require "rack/session#{ adapter_name }"</code>.
Custom storage technologies are autoloaded via <code>require "rack/session#{ adapter_name }"</code>.
</p>

The second argument passed to `sessions` is a Hash of options that are **passed to the adapter**.
@@ -9,7 +9,7 @@ This section shares a few techniques to make this possible.

## Prepare

In our settings (`apps/web/application.rb`), there is code block that allows to share the code for **all the actions** of our application.
In our settings (`apps/web/application.rb`), there is a code block that allows us to share the code for **all the actions** of our application.
When an action includes the `Web::Action` module, that block code is yielded within the context of that class.
This is heavily inspired by Ruby Module and its `included` hook.

@@ -73,8 +73,8 @@ Code included via <code>prepare</code> is available for ALL the actions of an ap

### Skipping A Callback

Let's say we have included `Authentication` globally, but want to skip the execution its callback for certain resources.
A typical use case is to let unauthenticated requests to reach our sign in form.
Let's say we have included `Authentication` globally, but want to skip the execution of its callback for certain resources.
A typical use case is to redirect unauthenticated requests to our sign in form.

The solution is really simple and elegant at the same time: override that method.

@@ -127,7 +127,7 @@ module Web::Controllers::Books
end
```

We have defined a module for our behavior to share, let's include it all the actions that need it.
We have defined a module for our behavior to share, let's include it in all the actions that need it.

```ruby
# apps/web/controllers/books/update.rb
@@ -4,12 +4,12 @@ title: Lotus - Guides - Action Testing

# Testing

Lotus pays a lot of attention for code testability and it offers advanced features to make our life easier.
Lotus pays a lot of attention to code testability and it offers advanced features to make our lives easier.
The framework supports Minitest (default) and RSpec.

## Unit Tests

First of all, action can be unit tested.
First of all, actions can be unit tested.
That means we can instantiate, excercise and verify expectations **directly on actions instances**.

```ruby
@@ -41,16 +41,16 @@ All the dependencies and the application code (actions, views, entities, etc..)
**Boot time is slow in this case.**

<p class="notice">
The entire test suite can be ran via default Rake task. It loads all the dependencies, and the application code.
The entire test suite can be run via default Rake task. It loads all the dependencies, and the application code.
</p>

The second scenario can be done via: `ruby -Ispec spec/web/controllers/dashboard/index_spec.rb` (or `rspec spec/web/controllers/dashboard/index_spec.rb` if we use RSpec).
When we run a single file example **only the framework and the application settings are loaded**.

Please note the `require_relative` line in the example.
It's **auto generated for us** and it's needed to load the current action under test.
This mechanism allows to run unit tests in **isolation**.
**Boot time a magnitude faster**.
This mechanism allows us to run unit tests in **isolation**.
**Boot time is magnitudes faster**.

<p class="notice">
A single unit test can be run directly. It only loads the dependencies, but not the application code.
@@ -111,9 +111,9 @@ Simulating request params and headers is simple for Lotus actions. We pass them
There are cases where we want to verify the internal state of an action.
Imagine we have a classic user profile page, like depicted in the example above.
The action asks for a record that corresponds to the given id, and then set a `@user` instance variable.
How to verify that the record is the one that we are looking for?
How do we verify that the record is the one that we are looking for?

Because we want to make `@user` available to the outside world, we're gonna use an [_exposure_](/guides/actions/exposures).
Because we want to make `@user` available to the outside world, we're going to use an [_exposure_](/guides/actions/exposures).
They are used to pass a data payload between an action and the corresponding view.
When we do `expose :user`, Lotus creates a getter (`#user`), so we can easily assert if the record is the right one.

@@ -163,12 +163,12 @@ The internal state of an action can be easily verified with <em>exposures</em>.

### Dependency Injection

During unit testing, we may want to use mocks to make tests faster or to avoid to hit external systems like databases, file system or remote services.
During unit testing, we may want to use mocks to make tests faster or to avoid hitting external systems like databases, file system or remote services.
Because we can instantiate actions during tests, there is no need to use testing antipatterns (eg. `any_instance_of`, or `UserRepository.stub(:find)`).
Instead, we can just specify which collaborators we want to use via _dependency injection_.

Let's rewrite the test above to not hit the database.
We're gonna use RSpec for this example as it has a nicer API for mocks (doubles).
Let's rewrite the test above so that it does not hit the database.
We're going to use RSpec for this example as it has a nicer API for mocks (doubles).

```ruby
# spec/web/controllers/users/show_spec.rb
@@ -212,15 +212,15 @@ end
```

<p class="warning">
Please use carefully doubles in unit tests. Always verify that the mocks are in sync with the corresponding production code.
Please be careful using doubles in unit tests. Always verify that the mocks are in a true representation of the corresponding production code.
</p>

## Requests Tests

Unit tests are a great tool to assert that low level interfaces works as expected.
We always advice to combine them with integration tests.
We always advise combining them with integration tests.

In case of Lotus web applications, we can write features (aka acceptance tests) with Capybara, but what to use in case we are building HTTP APIs?
In the case of Lotus web applications, we can write features (aka acceptance tests) with Capybara, but what do we use when we are building HTTP APIs?
The tool that we suggest is `rack-test`.

Imagine we have an API application mounted at `/api/v1` in our `Lotus::Container`.
@@ -252,7 +252,7 @@ end
```

In this case we don't care too much about the internal state of the action, but about the output visible to the external world.
This is why we haven't set `user` as an instance variable and neither we had exposed it.
This is why we haven't set `user` as an instance variable and why we haven't exposed it.

```ruby
# spec/api_v1/requests/users_spec.rb

0 comments on commit bb94aa2

Please sign in to comment.
You can’t perform that action at this time.