trickydiddy
trickydiddy

Reputation: 587

How can I create checkboxes, set checkbox values, sum them up to one task model value and sort tasks according to that value?

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:

  1. Task (important and urgent checbox checked)
  2. Task (important checkbox checked, urgent is not checked)
  3. Task (urgent checkbox is checked, important is not checked)
  4. Task (no checboxes are checked)

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

Answers (2)

Cœur
Cœur

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

Ben Hawker
Ben Hawker

Reputation: 949

Q1: How can I make checkboxes, set checkbox values and sum them up to one task model value?

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

Q2: How can I sort the tasks according to the summed up value?

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

Q3: How can I sort the tasks by the created/updated time as second criteria?

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

Related Questions