Reputation: 587
I'm making a to-do list with Rails. I want to have two checkboxes for every task ("Important" and "Urgent"). I want to sort those tasks according to two criteria. First criteria are the checkboxes and the second criteria should be the time where the task has been created or updated. So with the first criteria there are 4 priorities which the tasks should be sorted:
If there are multiple tasks with the same priority those should be sorted descending by the second criteria but within the first criteria.
I would create a migration to add an integer to the task model and then set the checkboxes to the values: "important = 2" and "urgent = 1" (unchecked value = 0). Those checkbox values should be summed up and linked to the integer in the task model and then I would sort them in the task view.
Questions:
index.html.erb (task view)
<h1>To Do</h1>
<table>
<thead>
<th>Content</th>
<th>State</th>
<th></th>
<th></th>
<th></th>
<th></th>
</thead>
<tbody>
<% @to_do.each do |task| %>
<tr>
<td><%= task.content %></td>
<td><%= task.state %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Destroy', task_path(task), method: :delete, data: { confirm: "Are you sure to delete this task?" } %></td>
<td><%= link_to 'Mark as Doing', change_task_path(task, state: "doing"), method: :put %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<h1>Doing</h1>
<table>
<thead>
<th>Content</th>
<th>State</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</thead>
<tbody>
<% @doing.each do |task| %>
<tr>
<td><%= task.content %></td>
<td><%= task.state %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Destroy', task_path(task), method: :delete, data: { confirm: "Are you sure to delete this task?" } %></td>
<td><%= link_to 'Mark as To Do', change_task_path(task, state: "to_do"), method: :put %></td>
<td><%= link_to 'Mark as Done', change_task_path(task, state: "done"), method: :put %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<h1>Done</h1>
<table>
<thead>
<th>Content</th>
<th>State</th>
<th></th>
<th></th>
<th></th>
<th></th>
</thead>
<tbody>
<% @done.each do |task| %>
<tr>
<td><%= task.content %></td>
<td><%= task.state %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Destroy', task_path(task), method: :delete, data: { confirm: "Are you sure to delete this task?" } %></td>
<td><%= link_to 'Mark as Doing', change_task_path(task, state: "doing"), method: :put %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Task', new_task_path %>
new.html.erb (task new view)
<h1>New Task</h1>
<%= form_for(@task) do |f| %>
<%= f.text_field :content, placeholder: "Content", class: "formfield" %>
<%= f.submit "Save Content", class: "form_button" %>
<% end %>
<%= link_to 'Back', tasks_path %>
tasks_controller.rb
class TasksController < ApplicationController
before_action :logged_in_user
before_action :set_task, only: [:show, :edit, :update, :destroy, :change]
def index
@to_do = current_user.tasks.where(state: "to_do")
@doing = current_user.tasks.where(state: "doing")
@done = current_user.tasks.where(state: "done")
end
def show
end
def new
@task = Task.new
end
def edit
end
def create
@task = current_user.tasks.new(task_params)
if @task.save
flash[:success] = "You successfully created a Task!"
redirect_to tasks_path
else
render 'new_task_path'
end
end
def update
@task.update(task_params)
if @task.save
flash[:success] = "You successfully updated a Task!"
redirect_to tasks_path
else
render 'edit_task_path'
end
end
def destroy
@task.destroy
flash[:success] = "You successfully deleted a Task!"
redirect_to tasks_path
end
def change
@task.update_attributes(state: params[:state])
flash[:success] = "You successfully changed the State!"
redirect_to tasks_path
end
private
def set_task
@task = Task.find(params[:id])
end
def task_params
params.require(:task).permit(:content, :state)
end
end
Upvotes: 0
Views: 251
Reputation: 38717
Solution by OP.
task.rb
class Task < ActiveRecord::Base
belongs_to :user
scope :important, -> { where(important: true) }
scope :urgent, -> { where(urgent: true) }
default_scope { order(:important => :desc, :urgent => :desc, :updated_at => :desc, :created_at => :desc) }
end
new.html.erb
<h1>New Task</h1>
<%= form_for(@task) do |f| %>
<%= f.text_field :content, placeholder: "Content", class: "formfield" %>
<strong>Important:</strong>
<%= f.check_box :important %>
<strong>Urgent:</strong>
<%= f.check_box :urgent %>
<%= f.submit "Save Content", class: "form_button" %>
<% end %>
<%= link_to 'Back', tasks_path %>
Upvotes: 1
Reputation: 949
I don't think that summing the checkbox values to one 'task model value' is the best solution. I would add both an Urgent and an Important column to your Task model. This is far more scalable in the long run and easier to work with generally. Then it's just a case using the Rails check_box_tag helper. http://apidock.com/rails/ActionView/Helpers/FormTagHelper/check_box_tag
If you have separate columns/attributes for the important and urgent you can create scopes on your task model to sort as you wish.
scope :important, -> { where(important: true) }
scope :urgent, -> { where(urgent: true) }
You can then chain your named scopes as you require.
Task.important.urgent
or maybe you can also specify a recent scope:
scope :recent, -> { order("posts.updated_at DESC") }
and then call:
Task.important.recent
which would run the following SQL query:
# SELECT "tasks".* FROM "tasks" WHERE "tasks"."important" = 'true'
# ORDER BY tasks.updated_at DESC
The above query sort of addresses this but you could also use:
Task.order(important: :asc, created_at: :desc)
Hope some of this is helpful.
Upvotes: 0