-
Notifications
You must be signed in to change notification settings - Fork 71
/
product.rb
190 lines (161 loc) · 5.85 KB
/
product.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# frozen_string_literal: true
class Product < ApplicationRecord
include Commentable
include Checkable
include Footprintable
include Watchable
include Reactionable
include WithAvatar
include Mentioner
include Searchable
include Bookmarkable
include Taskable
belongs_to :practice
belongs_to :user, touch: true
alias sender user
after_create ProductCallbacks.new
after_update ProductCallbacks.new
after_save ProductCallbacks.new
after_destroy ProductCallbacks.new
columns_for_keyword_search :body
validates :user, presence: true, uniqueness: { scope: :practice, message: '既に提出物があります。' }
validates :body, presence: true
paginates_per 50
mentionable_as :body
scope :ids_of_common_checked_with,
->(user) { where(practice: user.practices_with_checked_product).checked.pluck(:id) }
scope :unchecked, -> { where.not(id: Check.where(checkable_type: 'Product').pluck(:checkable_id)) }
scope :unassigned, -> { where(checker_id: nil) }
scope :self_assigned_product, ->(current_user_id) { where(checker_id: current_user_id) }
scope :self_assigned_and_replied_products, ->(user_id) { self_assigned_product(user_id).where.not(id: self_assigned_no_replied_product_ids(user_id)) }
scope :wip, -> { where(wip: true) }
scope :not_wip, -> { where(wip: false) }
scope :list, lambda {
with_avatar
.preload(:practice,
:comments,
{ user: :company },
{ checks: { user: { avatar_attachment: :blob } } })
}
scope :order_for_list, -> { order(created_at: :desc, id: :desc) }
scope :order_for_not_wip_list, -> { order(published_at: :desc, id: :desc) }
scope :order_for_self_assigned_list, -> { order(commented_at: :desc, published_at: :desc) }
def self.add_latest_commented_at
Product.all.includes(:comments).find_each do |product|
next if product.comments.blank?
product.update!(commented_at: product.comments.last.updated_at)
end
end
# rubocop:disable Metrics/MethodLength
def self.self_assigned_no_replied_product_ids(current_user_id)
sql = <<~SQL
WITH last_comments AS (
SELECT *
FROM comments AS parent
WHERE commentable_type = 'Product' AND id = (
SELECT id
FROM comments AS child
WHERE parent.commentable_id = child.commentable_id
AND commentable_type = 'Product'
ORDER BY created_at DESC LIMIT 1
)
),
self_assigned_products AS (
SELECT products.*
FROM products
WHERE checker_id = ?
)
SELECT self_assigned_products.id
FROM self_assigned_products
LEFT JOIN last_comments ON self_assigned_products.id = last_comments.commentable_id
WHERE last_comments.id IS NULL
OR self_assigned_products.checker_id != last_comments.user_id
ORDER BY self_assigned_products.created_at DESC
SQL
Product.find_by_sql([sql, current_user_id]).map(&:id)
end
def self.unchecked_no_replied_products_ids(current_user_id)
sql = <<~SQL
WITH last_comments AS (
SELECT *
FROM comments AS parent
WHERE commentable_type = 'Product' AND id = (
SELECT id
FROM comments AS child
WHERE parent.commentable_id = child.commentable_id
AND commentable_type = 'Product'
ORDER BY created_at DESC LIMIT 1
)
),
unchecked_products AS (
SELECT products.*
FROM products
LEFT JOIN checks ON products.id = checks.checkable_id AND checks.checkable_type = 'Product'
WHERE checks.id IS NULL AND wip = false
)
SELECT unchecked_products.id
FROM unchecked_products
LEFT JOIN last_comments ON unchecked_products.id = last_comments.commentable_id
WHERE last_comments.id IS NULL
OR last_comments.user_id != ?
ORDER BY unchecked_products.created_at DESC
SQL
Product.find_by_sql([sql, current_user_id]).map(&:id)
end
# rubocop:enable Metrics/MethodLength
def self.self_assigned_no_replied_products(current_user_id)
no_replied_product_ids = self_assigned_no_replied_product_ids(current_user_id)
Product.where(id: no_replied_product_ids)
.order(commented_at: :desc, published_at: :desc)
end
def self.unchecked_no_replied_products(current_user_id)
no_replied_products_ids = unchecked_no_replied_products_ids(current_user_id)
Product.where(id: no_replied_products_ids)
.order(created_at: :desc)
end
def completed?(user)
checks.where(user: user).present?
end
def change_learning_status(status)
learning = Learning.find_or_initialize_by(
user_id: user.id,
practice_id: practice.id
)
learning.update(status: status)
end
def last_commented_user
Rails.cache.fetch "/model/product/#{id}/last_commented_user" do
commented_users.last
end
end
def category(course)
Category.category(practice: practice, course: course)
end
def save_checker(current_user_id)
return false if other_checker_exists?(current_user_id)
self.checker_id = checker_id ? nil : current_user_id
Cache.delete_self_assigned_no_replied_product_count(current_user_id)
save!
end
def other_checker_exists?(current_user_id)
checker_id.present? && checker_id.to_s != current_user_id
end
def unassigned?
checker_id.nil?
end
def checker_name
checker_id ? User.find(checker_id).login_name : nil
end
def elapsed_days
t = published_at || created_at
((Time.current - t) / 1.day).to_i
end
def checker_avatar
checker_id ? User.find(checker_id).avatar_url : nil
end
def replied_status_changed?(previous_commented_user_id, current_commented_user_id)
is_replied_by_checker_previous = checker_id == previous_commented_user_id
is_replied_by_checker_current = checker_id == current_commented_user_id
is_replied_by_checker_previous != is_replied_by_checker_current
end
end