Add a tasks index page
Routing tasks
In order to access to the /tasks
path you need to add a tasks.rb
file in apps/main/web/routes/
that calls the view controller that respond to this request:
# frozen_string_literal: true
module Todo
module Main
class Web
route 'tasks' do |r|
r.is do
r.get do
r.view 'tasks.index'
end
end
end
end
end
end
A view controller for tasks index
Then the view controller for Tasks::Index
should be in the file: apps/main/lib/todo/main/views/tasks/index.rb
. It needs to include the Todo::Repositories::TasksRepo
that gives access to the tasks table content. It needs to expose the tasks array to the template.
# frozen_string_literal: true
require 'todo/main/view/controller'
require 'todo/main/import'
module Todo
module Main
module Views
module Tasks
class Index < Main::View::Controller
include Import['core.repositories.tasks_repo']
configure do |config|
config.template = 'tasks/index'
end
expose :tasks
private
def tasks
tasks_repo.tasks.to_a
end
end
end
end
end
end
The view template
And the view apps/main/web/templates/tasks/index.html.slim
builds a html list with the tasks array.
h1 Tasks
ul.tasks
- tasks.each do |task|
li.task
span = task.description
Adding tasks from console
Let's add some tasks in the console in order to see it working.
$ bin/console
> user = Todo::Container['repositories.users_repo'].users.first
> tasks_repo = Todo::Container['repositories.tasks_repo']
> tasks_repo.create(description: 'My first task', user_id: user.id)
The tasks are not user-scoped yet. If you inspect the file log/development.log
you will find the SQL used to respond the get /tasks
request.
Started GET "/tasks" for 127.0.0.1 at 2017-10-08 15:37:39 -0300
Loaded :users in 1.55ms SELECT "id", "email", "password_digest", "created_at", "updated_at" FROM "users" WHERE ("users"."id" = 1) ORDER BY "users"."id"
Loaded :tasks in 0.4ms SELECT "id", "description", "completed", "user_id", "created_at", "updated_at" FROM "tasks" ORDER BY "tasks"."id"
Finished GET "/tasks" for 127.0.0.1 in 33.67ms [Status: 200]
There is not a WHERE
condition when reading tasks. So, next to do is:
Scoping tasks for current user
I want a user can see its own tasks, but he/she should not see a task that is not own. Then the view controller needs to know the current_user
, so it will be passed as a parameter.
And I want to put all the logic of access for each resource in a common place, the folder apps/main/lib/todo/main/policies/
. The policy for tasks will be located in the file tasks_scope.rb
.
The apps/main/lib/todo/main/policies/tasks_scope.rb
will import the TasksRepo
and will be called with a user
, then it will return the relation of tasks that belong to the user received.
# frozen_string_literal: true
require 'todo/main/import'
module Todo
module Main
module Policies
class TasksScope
include Import['core.repositories.tasks_repo']
def call(user)
tasks_repo.tasks.where(user_id: user.id)
end
end
end
end
end
The view controller: apps/main/lib/todo/main/views/tasks/index.rb
does not need any more the TasksRepo
because it will ask to the Policies::TaskScope
for the current_user
's tasks. And current_user
will be received as a private_expose
.
# frozen_string_literal: true
require 'todo/main/view/controller'
require 'todo/main/import'
module Todo
module Main
module Views
module Tasks
class Index < Main::View::Controller
include Import['policies.tasks_scope']
configure do |config|
config.template = 'tasks/index'
end
private_expose :current_user
expose :tasks do |current_user|
tasks_scope.(current_user).to_a
end
end
end
end
end
end
Last to make it work, is to add the current_user
as a parameter for the view call in apps/main/web/routes/tasks.rb
.
# frozen_string_literal: true
module Todo
module Main
class Application
route 'tasks' do |r|
r.is do
r.get do
r.view 'tasks.index', current_user: current_user
end
end
end
end
end
end
And the user will see his/her own tasks exclusively. And the SQL at the log reflects this behavior.
Started GET "/tasks" for 127.0.0.1 at 2017-10-08 15:44:47 -0300
Loaded :users in 1.7ms SELECT "id", "email", "password_digest", "created_at", "updated_at" FROM "users" WHERE ("users"."id" = 1) ORDER BY "users"."id"
Loaded :tasks in 0.61ms SELECT "id", "description", "completed", "user_id", "created_at", "updated_at" FROM "tasks" WHERE ("user_id" = 1) ORDER BY "tasks"."id"
Finished GET "/tasks" for 127.0.0.1 in 36.16ms [Status: 200]