Skip to content

Commit

Permalink
search_helperのメソッドを元に戻す実装にした
Browse files Browse the repository at this point in the history
  • Loading branch information
nakamu-kazu222 committed Jan 15, 2025
1 parent 3d3e414 commit f79c125
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 52 deletions.
2 changes: 1 addition & 1 deletion app/controllers/searchables_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def index
@word = params[:word].to_s
@document_type = params[:document_type]&.to_sym || :all

result = Searcher.search(@word, document_type: @document_type, current_user: current_user)
result = Searcher.search(@word, document_type: @document_type, current_user:)
@searchables = Kaminari.paginate_array(result.uniq).page(params[:page]).per(PER_PAGE)
end
end
88 changes: 67 additions & 21 deletions app/helpers/search_helper.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,79 @@
# frozen_string_literal: true

module SearchHelper
extend ActiveSupport::Concern
def self.matched_document(searchable)
if searchable.instance_of?(Comment)
searchable.commentable_type.constantize.find(searchable.commentable_id)
elsif searchable.instance_of?(Answer) || searchable.instance_of?(CorrectAnswer)
searchable.question
else
searchable
end
end

def searchable_url(searchable)
case searchable
when SearchResult
searchable.url
when Comment
"#{searchable.commentable.url}#comment_#{searchable.id}"
when CorrectAnswer, Answer
Rails.application.routes.url_helpers.question_path(searchable.question, anchor: "answer_#{searchable.id}")
else
helper_method = "#{searchable.class.name.underscore}_path"
Rails.application.routes.url_helpers.send(helper_method, searchable)
end
rescue NoMethodError
raise NoMethodError, "Route for #{searchable.class.name} is not defined. Please check your routes."
end

included do
def url
case self
when Comment
"#{commentable.url}#comment_#{id}"
when CorrectAnswer
Rails.application.routes.url_helpers.question_path(question, anchor: "answer_#{id}")
when Answer
Rails.application.routes.url_helpers.question_path(question, anchor: "answer_#{id}")
def filtered_message(searchable)
case searchable
when SearchResult
searchable.summary
when Comment
commentable = searchable.commentable_type.constantize.find(searchable.commentable_id)
if policy(commentable).show? || (commentable.is_a?(Practice) && commentable.open_product?)
searchable.body
else
helper_method = "#{self.class.name.underscore}_path"
Rails.application.routes.url_helpers.send(helper_method, self)
'該当プラクティスを修了するまで他の人の提出物へのコメントは見れません。'
end
rescue NoMethodError
raise NoMethodError, "Route for #{self.class.name} is not defined. Please check your routes."
when Product
searchable.body.presence || '本文がありません。'
else
searchable.try(:description) || '本文がありません。'
end
end

def formatted_summary(word)
target_text = respond_to?(:body) ? body : description
return target_text if word.blank?
def comment_or_answer?(searchable)
if searchable.is_a?(SearchResult)
%w[comment answer correct_answer].include?(searchable.model_name)
else
searchable.is_a?(Comment) || searchable.is_a?(Answer)
end
end

words = word.split(/[[:blank:]]+/)
words.reduce(target_text) do |text, single_word|
Searcher.highlight_word(text, single_word)
end
def talk?(searchable)
if searchable.is_a?(SearchResult)
searchable.model_name == 'user' && searchable.talk.present?
else
searchable.instance_of?(User) && searchable.talk.present?
end
end

def user?(searchable)
if searchable.is_a?(SearchResult)
searchable.model_name == 'user'
else
searchable.instance_of?(User)
end
end

def created_user(searchable)
if searchable.is_a?(SearchResult)
User.find_by(id: searchable.user_id)
else
searchable.respond_to?(:user) ? searchable.user : nil
end
end
end
8 changes: 4 additions & 4 deletions app/models/concerns/searchable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def params_for_keyword_search(searched_values = {})
{ _join_column_names => word }
end
end
{ combinator: 'and', groupings: groupings }
{ combinator: 'and', groupings: }
end

def word_to_groupings(word)
Expand Down Expand Up @@ -74,11 +74,11 @@ def primary_role
end

def formatted_updated_at
if self.is_a?(SearchResult)
self.formatted_updated_at
if is_a?(SearchResult)
formatted_updated_at
else
weekdays = { 'Sunday' => '日', 'Monday' => '月', 'Tuesday' => '火', 'Wednesday' => '水',
'Thursday' => '木', 'Friday' => '金', 'Saturday' => '土' }
'Thursday' => '木', 'Friday' => '金', 'Saturday' => '土' }
day_name = updated_at.strftime('%A')
updated_at.strftime("%Y年%m月%d日(#{weekdays[day_name]}) %H:%M")
end
Expand Down
12 changes: 7 additions & 5 deletions app/models/search_result.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# frozen_string_literal: true

class SearchResult
include SearchHelper

attr_accessor :url, :title, :summary, :formatted_summary, :user_id,
:login_name, :formatted_updated_at, :model_name, :label,
:wip, :commentable_user, :commentable_type, :primary_role

def initialize(searchable, word)
@url = searchable.try(:url)
@url = searchable_url(searchable)
@title = Searcher.fetch_title(searchable)
@summary = searchable.try(:summary)
@formatted_summary = searchable.formatted_summary(word)
@summary = filtered_message(searchable)
@formatted_summary = Searcher.highlight_word(@summary, word)
@user_id = searchable.is_a?(User) ? searchable.id : searchable.try(:user_id)
@login_name = Searcher.fetch_login_name(searchable)
@formatted_updated_at = searchable.formatted_updated_at
@formatted_updated_at = searchable.respond_to?(:formatted_updated_at) ? searchable.formatted_updated_at : searchable.updated_at.strftime('%Y年%m月%d日 %H:%M')
@model_name = searchable.class.name.underscore
@label = Searcher.fetch_label(searchable)
@wip = searchable.try(:wip)
@commentable_user = Searcher.fetch_commentable_user(searchable)
@commentable_type = I18n.t("activerecord.models.#{searchable.try(:commentable)&.try(:model_name)&.name&.underscore}", default: '')
@primary_role = searchable.primary_role
@primary_role = created_user(searchable)&.primary_role
end
end
56 changes: 35 additions & 21 deletions app/models/searcher.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class Searcher
include SearchHelper

DOCUMENT_TYPES = [
['すべて', :all],
['お知らせ', :announcements],
Expand All @@ -16,7 +18,13 @@ class Searcher

AVAILABLE_TYPES = DOCUMENT_TYPES.map(&:second) - %i[all] + %i[comments answers]

def self.search(word, document_type: :all, current_user:)
def self.fetch_url(searchable)
searchable_url(searchable)
rescue NoMethodError
nil
end

def self.search(word, current_user:, document_type: :all)
words = word.split(/[[:blank:]]+/).reject(&:blank?)
searchables = case document_type
when :all
Expand All @@ -29,17 +37,22 @@ def self.search(word, document_type: :all, current_user:)
result_for(document_type, words).sort_by(&:updated_at).reverse
end

if current_user.admin?
searchables = searchables.reject { |searchable| searchable.instance_of?(Talk) }
else
searchables = searchables.reject do |searchable|
searchable.instance_of?(Talk) && searchable.user_id != current_user.id
end
end
searchables = if current_user.admin?
searchables.reject { |searchable| searchable.instance_of?(Talk) }
else
searchables.reject do |searchable|
searchable.instance_of?(Talk) && searchable.user_id != current_user.id
end
end

delete_comment_of_talk!(searchables, current_user)

searchables.map { |searchable| SearchResult.new(searchable, word) }
searchables.map do |searchable|
SearchResult.new(
SearchHelper.matched_document(searchable),
word
)
end
end

def self.fetch_login_name(searchable)
Expand Down Expand Up @@ -67,6 +80,8 @@ def self.fetch_title(searchable)
def self.fetch_label(searchable)
if searchable.is_a?(User)
searchable.avatar_url
elsif searchable.is_a?(Talk)
nil
else
searchable.label
end
Expand All @@ -78,13 +93,15 @@ def self.result_for_all(words)
username = user_filter.delete_prefix('user:')
user = User.find_by(login_name: username)
return [] unless user

AVAILABLE_TYPES
.reject { |type| type == :users }
.flat_map do |type|
model = model(type)
next [] unless model.column_names.include?('user_id') || model.column_names.include?('last_updated_user_id')

if type == :practices
model.where("last_updated_user_id = ?", user.id)
model.where('last_updated_user_id = ?', user.id)
else
model.where(user_id: user.id)
end
Expand Down Expand Up @@ -115,14 +132,14 @@ def self.result_for(type, words, commentable_type: nil)
return [] unless user

results = if type == :practices
model(type).where("user_id = ? OR last_updated_user_id = ?", user.id, user.id)
model(type).where('user_id = ? OR last_updated_user_id = ?', user.id, user.id)
else
model(type).where(user_id: user.id)
end
else
results = if commentable?(type)
model(type).search_by_keywords(words:, commentable_type:) +
Comment.search_by_keywords(words:, commentable_type: model_name(type))
Comment.search_by_keywords(words:, commentable_type: model_name(type))
else
model(type).search_by_keywords(words:, commentable_type:)
end
Expand All @@ -133,14 +150,13 @@ def self.result_for(type, words, commentable_type: nil)
def self.result_matches_keyword?(result, word)
return false unless result

if word.match(/^user:(\w+)$/)
if word =~ /^user:(\w+)$/
username = Regexp.last_match(1)
if result.is_a?(Practice)
return result.user&.login_name == username unless result.is_a?(Practice)

user = User.find_by(id: result.last_updated_user_id)
return user&.login_name == username
else
return result.user&.login_name == username
end

end
searchable_fields = [result.try(:title), result.try(:body), result.try(:description)]
searchable_fields.any? { |field| field.to_s.include?(word) }
Expand Down Expand Up @@ -170,14 +186,12 @@ def self.commentable?(document_type)

def self.delete_comment_of_talk!(searchables, current_user)
searchables.reject! do |searchable|
if searchable.instance_of?(Comment) && searchable.commentable.instance_of?(Talk)
searchable.commentable.user_id != current_user.id && !current_user.admin?
end
searchable.commentable.user_id != current_user.id && !current_user.admin? if searchable.instance_of?(Comment) && searchable.commentable.instance_of?(Talk)
end
end

def self.highlight_word(text, word)
return '' unless text.present? && word.present?
return text unless text.present? && word.present?

sanitized_word = Regexp.escape(word)
text.gsub(/(#{sanitized_word})/i, '<strong class="matched_word">\1</strong>')
Expand Down
1 change: 1 addition & 0 deletions app/views/searchables/index.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ hr.a-border
.container.is-md
.card-list.a-card
- @searchables.each do |searchable|
- next if searchable.model_name == 'talk'
span class="card-list-item is-#{searchable.model_name}"
.card-list-item__inner
- searchable_user = User.find_by(id: searchable.user_id)
Expand Down

0 comments on commit f79c125

Please sign in to comment.