diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb
index b857caa0..39e9d69d 100644
--- a/app/controllers/documents_controller.rb
+++ b/app/controllers/documents_controller.rb
@@ -3,34 +3,15 @@ class DocumentsController < ApplicationController
before_action :set_document, only: %i[ show edit update destroy ]
protect_from_forgery :except => [:api_markdown]
- def search_check(param)
- if param.present?
- key_words = param.split(/[\p{blank}\s]+/)
- grouping_hash = key_words.reduce({}) {|hash, word| hash.merge(word => {content_or_creator_screen_name_or_description_or_project_name_or_location_cont: word})}
- else
- nil
- end
- end
-
- def sort_check(param)
- if param.present?
- sort_column = []
- sort_column << param
- else
- "start_at DESC"
- end
- end
-
# GET /documents or /documents.json
def index
- if params[:q].nil?
- @q = Document.ransack(params[:q])
- @q.sorts = "start_at DESC"
- else
- @q = Document.ransack({combinator: 'and', groupings: search_check(params[:q][:content_or_creator_screen_name_or_description_or_project_name_or_location_cont])})
- @q.sorts = sort_check(params[:q][:s])
- end
- @documents = @q.result.page(params[:page]).per(50).includes(:user)
+ search_query = { combinator: "and", groupings: split_into_search_queries(params.dig(:q, :text_cont)) }
+ search_query.merge!({ tags_id_eq: params[:tag_id] }) if params[:tag_id].present?
+
+ @q = Document.ransack(search_query)
+ @q.sorts = build_sort_query_with_default(params.dig(:q, :s))
+ @documents = @q.result.page(params[:page]).per(50).includes(:user, :creator, :project, :tags)
+ @tags = Tag.all
end
# GET /documents/1 or /documents/1.json
@@ -130,4 +111,26 @@ def parse_tag_names(tag_names)
end
end
+ # Build ransack AND search query from params
+ # Example: { text_cont: "foo bar" } => [{ text_cont: "foo" }, { text_cont: "bar" }]
+ def split_into_search_queries(param)
+ return nil if param.nil? || param.blank?
+
+ # Split keyword and build AND search condition
+ queries = []
+ words = param.split(/[\p{blank}\s]+/)
+ words.each do |word|
+ queries << { text_cont: word }
+ end
+
+ queries
+ end
+
+ def build_sort_query_with_default(param)
+ if param.present?
+ param
+ else
+ "start_at DESC"
+ end
+ end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 72d9359b..97168e5c 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -4,7 +4,7 @@ class ProjectsController < ApplicationController
# GET /projects or /projects.json
def index
- @projects = Project.all.includes(:user)
+ @projects = Project.all.includes(:user, tasks: [:state, :tags, :assigner, :project])
end
# GET /projects/1 or /projects/1.json
diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb
index 84b7176d..a946031c 100644
--- a/app/controllers/tasks_controller.rb
+++ b/app/controllers/tasks_controller.rb
@@ -3,43 +3,22 @@ class TasksController < ApplicationController
before_action :set_task, only: %i[ show edit update destroy ]
before_action :get_form_data, only: %i[ new edit ]
- def search_check(param)
- if param.present?
- key_words = param.split(/[\p{blank}\s]+/)
- grouping_hash = key_words.reduce({}) { |hash, word| hash.merge(word => { content_or_assigner_screen_name_or_description_or_project_name_cont: word }) }
- else
- nil
- end
- end
-
- def sort_check(param)
- if param.present?
- sort_column = []
- sort_column << "state.priority DESC" << param
- else
- "state.priority DESC"
- end
- end
-
# GET /tasks or /tasks.json
def index
- if params[:q].nil?
- @q = Task.joins(:state).ransack(params[:q])
- @q.sorts = ["state.priority DESC", "due_at ASC"]
- else
- @q = Task.joins(:state).ransack({combinator: 'and', groupings: search_check(params[:q][:content_or_assigner_screen_name_or_description_or_project_name_cont])})
- @q.sorts = sort_check(params[:q][:s])
- end
+ search_query = { combinator: "and", groupings: split_into_search_queries(params.dig(:q, :text_cont)) }
- @show_all = params[:all] == 'true'
- tasks_query = @q.result
+ session[:show_all] = params[:all] == 'true' if params[:all].present?
+ search_query.merge!({ assigner_id_eq: current_user.id }) unless session[:show_all]
- if params[:only_todo] == '1'
- tasks_query = tasks_query.merge(Task.active)
- end
-
- tasks_query = tasks_query.joins(:user).where(users: {screen_name: current_user&.screen_name}) unless @show_all
- @tasks = tasks_query.page(params[:page]).per(50).includes(:user, :state)
+ session[:only_todo] = params[:only_todo] if params[:only_todo].present?
+ search_query.merge!({ task_state_id_eq: TaskState.todo.id }) if session[:only_todo] == "1"
+
+ search_query.merge!({ tags_id_eq: params[:tag_id] }) if params[:tag_id].present?
+
+ @q = Task.ransack(search_query)
+ @q.sorts = build_sort_query_with_default(params.dig(:q, :s))
+ @tasks = @q.result.page(params[:page]).per(50).includes(:user, :project, :tags, :assigner, :state)
+ @tags = Tag.all
end
# GET /tasks/1 or /tasks/1.json
@@ -136,4 +115,29 @@ def parse_tag_names(tag_names)
tag ? tag : Tag.create(name: tag_name)
end
end
+
+ # Build ransack AND search query from params
+ # Example: { text_cont: "foo bar" } => [{ text_cont: "foo" }, { text_cont: "bar" }]
+ def split_into_search_queries(param)
+ return nil if param.nil? || param.blank?
+
+ # Split keyword and build AND search condition
+ queries = []
+ words = param.split(/[\p{blank}\s]+/)
+ words.each do |word|
+ queries << { text_cont: word }
+ end
+
+ queries
+ end
+
+ def build_sort_query_with_default(param)
+ query = ["state_priority DESC"]
+ if param.present?
+ query << param
+ else
+ query << "due_at ASC"
+ end
+ query
+ end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 163290b9..8b99c224 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -2,4 +2,12 @@ module ApplicationHelper
def tag_label(tag)
raw %( #{tag.name})
end
+
+ def url_with_query(url, key, value)
+ uri = URI(url)
+ query = Rack::Utils.parse_query(uri.query)
+ query[key] = value
+ uri.query = query.to_query
+ uri.to_s
+ end
end
diff --git a/app/helpers/documents_helper.rb b/app/helpers/documents_helper.rb
index 242b4fce..8900fb76 100644
--- a/app/helpers/documents_helper.rb
+++ b/app/helpers/documents_helper.rb
@@ -1,2 +1,15 @@
module DocumentsHelper
+ def preserve_other_params(except: [])
+ forms = []
+ params.except(:controller, :action, :commit, *except).each do |key, value|
+ if key == 'q'
+ value.each do |q_key, q_value|
+ forms << hidden_field_tag("q[#{q_key}]", q_value)
+ end
+ else
+ forms << hidden_field_tag(key, value)
+ end
+ end
+ forms.join.html_safe
+ end
end
diff --git a/app/helpers/tasks_helper.rb b/app/helpers/tasks_helper.rb
index 1e5645f6..b153400b 100644
--- a/app/helpers/tasks_helper.rb
+++ b/app/helpers/tasks_helper.rb
@@ -7,4 +7,19 @@ def days_to_deadline_as_string(task)
""
end
end
+
+ def preserve_other_params(except: [])
+ forms = []
+ params.except(:controller, :action, :commit, *except).each do |key, value|
+ if key == 'q'
+ value.each do |q_key, q_value|
+ forms << hidden_field_tag("q[#{q_key}]", q_value)
+ end
+ else
+ forms << hidden_field_tag(key, value)
+ end
+ end
+ p forms
+ forms.join.html_safe
+ end
end
diff --git a/app/models/document.rb b/app/models/document.rb
index 6ecc5f1c..9d461bfd 100644
--- a/app/models/document.rb
+++ b/app/models/document.rb
@@ -14,8 +14,10 @@ class Document < ApplicationRecord
#validates :project, presence: true
before_validation :add_unique_action_item_marker
+ ransack_alias :text, :content_or_creator_screen_name_or_description_or_project_name_or_location_cont
+
def self.ransackable_attributes(auth_object = nil)
- ["content", "created_at", "creator_id", "description", "end_at", "id", "location", "project_id", "start_at", "updated_at"]
+ ["content", "created_at", "creator_id", "description", "end_at", "id", "location", "project_id", "start_at", "updated_at", "text"]
end
def self.ransackable_associations(auth_object = nil)
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 54280602..2a690828 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -5,6 +5,10 @@ class Tag < ApplicationRecord
has_many :documents, through: :document_tags, dependent: :restrict_with_exception
validates :name, presence: true, uniqueness: true
+ def self.ransackable_attributes(auth_object = nil)
+ [ "id", "name" ]
+ end
+
def self.order_by_popularity
self.find_by_sql <<~'SQL'
SELECT
diff --git a/app/models/task.rb b/app/models/task.rb
index 0002e1d4..24478ea9 100644
--- a/app/models/task.rb
+++ b/app/models/task.rb
@@ -15,9 +15,11 @@ class Task < ApplicationRecord
validates :content, presence: true
+ ransack_alias :text, :content_or_assigner_screen_name_or_description_or_project_name
+
def self.ransackable_attributes(auth_object = nil)
- [ "assigner_id", "content", "created_at", "creator_id", "description", "due_at", "id", "project_id", "tag_id", "task_state_id", "updated_at" ]
- end
+ [ "assigner_id", "content", "created_at", "creator_id", "description", "due_at", "id", "project_id", "tag_id", "task_state_id", "updated_at", "text" ]
+ end
def self.ransackable_associations(auth_object = nil)
[ "assigner", "project", "state", "tags", "task_tags", "user" ]
diff --git a/app/models/task_state.rb b/app/models/task_state.rb
index 7236730d..a807bb08 100644
--- a/app/models/task_state.rb
+++ b/app/models/task_state.rb
@@ -7,4 +7,16 @@ class TaskState < ApplicationRecord
def self.ransackable_attributes(auth_object = nil)
[ "priority" ]
end
+
+ def self.todo
+ @todo ||= find_by(name: 'todo')
+ end
+
+ def self.done
+ @done ||= find_by(name: 'done')
+ end
+
+ def self.draft
+ @draft ||= find_by(name: 'draft')
+ end
end
diff --git a/app/views/documents/index.html.erb b/app/views/documents/index.html.erb
index c15f2f02..86ebde80 100644
--- a/app/views/documents/index.html.erb
+++ b/app/views/documents/index.html.erb
@@ -1,3 +1,7 @@
+<% content_for :tag_list do %>
+ <%= render partial: "layouts/tag_list", locals: { base_link: request.original_url } %>
+<% end %>
+
<%= render 'layouts/h1', title: "文書一覧" %>
@@ -18,10 +22,11 @@
<%= search_form_for @q, class: "d-flex align-items-center w-100" do |f| %>
- <%= f.text_field :content_or_creator_screen_name_or_description_or_project_name_or_location_cont,
- class: "form-control me-2",
- placeholder: '検索ワードを入力して下さい',
+ <%= f.text_field :text_cont,
+ class: "form-control me-2",
+ placeholder: '検索ワードを入力して下さい',
style: "flex: 1;" %>
+ <%= preserve_other_params(except: [:q]) %>
<%= f.submit "検索", class: "btn btn-primary" %>
<% end %>
diff --git a/app/views/layouts/_tag_list.html.erb b/app/views/layouts/_tag_list.html.erb
index 27460f70..97a7c254 100644
--- a/app/views/layouts/_tag_list.html.erb
+++ b/app/views/layouts/_tag_list.html.erb
@@ -1,8 +1,11 @@
-
-
タグ一覧
-
- <% Tag.order_by_popularity.each do |tag| %>
- <%= link_to tag_label(tag), tag, class: "btn btn-primary btn-outline-primary" %>
- <% end %>
+
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index aa1d1e61..ff012b05 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -37,9 +37,7 @@
-
+ <%= yield :tag_list %>
diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb
index 3b73ac5c..bdd2b21b 100644
--- a/app/views/projects/index.html.erb
+++ b/app/views/projects/index.html.erb
@@ -9,14 +9,14 @@
<%= project.name %>
-
達成率 : <%= project.tasks.count { |task| task.completed? } %> / <%= project.tasks.count %>
+
達成率 : <%= project.tasks.size { |task| task.completed? } %> / <%= project.tasks.size %>
<% if logged_in? %>
<%= link_to '詳細', project, class: "btn btn-sm" %>
<%= link_to '編集', edit_project_path(project), class: "btn btn-sm" %>
- <% if project.tasks.count != 0 %>
+ <% if project.tasks.size != 0 %>
削除
<% else %>
<%= button_to '削除', project, method: :delete, data: { turbo_confirm: 'このプロジェクトを削除しますか?' }, class: "btn btn-sm text-black" %>
@@ -35,7 +35,7 @@
- <% if index < project.tasks.count - 1 %>
+ <% if index < project.tasks.size - 1 %>
<% end %>
diff --git a/app/views/tags/_tag.html.erb b/app/views/tags/_tag.html.erb
index d21ff4ca..68f9a0d7 100644
--- a/app/views/tags/_tag.html.erb
+++ b/app/views/tags/_tag.html.erb
@@ -1,15 +1,15 @@
<%= link_to tag.name, tag, class: "btn btn-primary" %>
-
タスク数 : <%= tag.tasks.count %>
-
文書数 : <%= tag.documents.count %>
+
タスク数 : <%= tag.tasks.size %>
+
文書数 : <%= tag.documents.size %>
<% if logged_in? %>
<%= link_to '詳細', tag, class: "btn btn-sm text-black" %>
<%= link_to '編集', edit_tag_path(tag), class: "btn btn-sm mx-2 text-black" %>
- <% if tag.tasks.count == 0 && tag.documents.count == 0 %>
+ <% if tag.tasks.size == 0 && tag.documents.size == 0 %>
<%= button_to '削除', tag, method: :delete, data: { turbo_confirm: 'このタグを削除しますか?' }, class: "btn btn-sm text-black" %>
<% else %>
削除
diff --git a/app/views/tasks/_task.html.erb b/app/views/tasks/_task.html.erb
index b4ac98e7..fcc989de 100644
--- a/app/views/tasks/_task.html.erb
+++ b/app/views/tasks/_task.html.erb
@@ -4,11 +4,11 @@
<%= turbo_frame_tag "task_#{task.id}" do %>
<% if task.completed? %>
- <%= button_to task, method: :patch, params: { task: { task_state_id: TaskState.find_by(name: 'todo').id } }, class: "btn btn-link p-0 border-0", style: "background: none;" do %>
+ <%= button_to task, method: :patch, params: { task: { task_state_id: TaskState.todo.id } }, class: "btn btn-link p-0 border-0", style: "background: none;" do %>
<% end %>
<% else %>
- <%= button_to task, method: :patch, params: { task: { task_state_id: TaskState.find_by(name: 'done').id } }, class: "btn btn-link p-0 border-0", style: "background: none;" do %>
+ <%= button_to task, method: :patch, params: { task: { task_state_id: TaskState.todo.id } }, class: "btn btn-link p-0 border-0", style: "background: none;" do %>
<% end %>
<% end %>
diff --git a/app/views/tasks/index.html.erb b/app/views/tasks/index.html.erb
index 7ecd5db3..900a9934 100644
--- a/app/views/tasks/index.html.erb
+++ b/app/views/tasks/index.html.erb
@@ -1,3 +1,7 @@
+<% content_for :tag_list do %>
+ <%= render partial: "layouts/tag_list", locals: { base_link: request.original_url } %>
+<% end %>
+
<%= render 'layouts/h1', title: "タスク一覧" %>
@@ -18,11 +22,11 @@
<%= search_form_for @q, class: "d-flex align-items-center w-100" do |f| %>
- <%= f.text_field :content_or_assigner_screen_name_or_description_or_project_name_cont,
- class: "form-control me-2",
- placeholder: '検索ワードを入力して下さい',
+ <%= f.text_field :text_cont,
+ class: "form-control me-2",
+ placeholder: '検索ワードを入力して下さい',
style: "flex: 1;" %>
- <%= hidden_field_tag :only_todo, params[:only_todo] if params[:only_todo].present? %>
+ <%= preserve_other_params(except: [:q]) %>
<%= f.submit "検索", class: "btn btn-primary" %>
<% end %>
@@ -31,25 +35,25 @@
<%= form_with url: request.path, method: :get, local: true, html: { class: "d-flex" } do %>
- <%= check_box_tag :only_todo, "1", params[:only_todo] == "1", onchange: "this.form.submit()" %>
+ <%= preserve_other_params(except: [:only_todo]) %>
+ <%= hidden_field_tag :only_todo, session[:only_todo] == '1' ? '0' : '1' %>
+ <%= check_box_tag "", "", checked: session[:only_todo] == "1", onchange: "this.form.submit()" %>
todoのみ
-
- <% if params[:q].present? %>
- <% params[:q].each do |key, value| %>
- <%= hidden_field_tag "q[#{key}]", value %>
- <% end %>
- <% end %>
<% end %>
-<% current_q_params = request.query_parameters.except(:controller, :action, :page) %>
-
- <%= link_to "#{current_user&.screen_name}のタスク", tasks_path(current_q_params.merge(all: 'false')), class: "nav-link #{'active' if !@show_all} link-text" %>
+ <%= link_to "#{current_user&.screen_name}のタスク",
+ url_with_query(request.original_url, "all", "false"),
+ class: "nav-link #{'active' if !session[:show_all]} link-text" %>
+
-
- <%= link_to 'すべてのタスク', tasks_path(current_q_params.merge(all: 'true')), class: "nav-link #{'active' if @show_all} link-text" %>
+ <%= link_to 'すべてのタスク',
+ url_with_query(request.original_url, "all", "true"),
+ class: "nav-link #{'active' if session[:show_all]} link-text" %>
@@ -58,7 +62,7 @@
<%= render @tasks %>
- <%= raw(paginate @tasks, params: current_q_params) %>
+ <%= raw(paginate @tasks) %>