This repository has been archived by the owner on Mar 6, 2018. It is now read-only.
/
ask.rb
263 lines (227 loc) · 7 KB
/
ask.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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# coding: utf-8
class Ask
include Mongoid::Document
include Mongoid::Timestamps
include Redis::Search
include BaseModel
field :title
field :body
# 最后回答时间
field :answered_at, :type => DateTime
field :answers_count, :type => Integer, :default => 0
field :comments_count, :type => Integer, :default => 0
field :topics, :type => Array, :default => []
field :spams_count, :type => Integer, :default => 0
field :spam_voter_ids, :type => Array, :default => []
field :views_count, :type => Integer, :default => 0
# 最后活动时间,这个时间应该设置为该问题下辖最后一条log的发生时间
field :last_updated_at, :type => DateTime
# 重定向问题编号
field :redirect_ask_id
index :created_at
index :topics
index :user_id
index :spams_count
# 提问人
belongs_to :user, :inverse_of => :asks
# 对指定人的提问
belongs_to :to_user, :class_name => "User"
# 回答
has_many :answers
# Log
has_many :logs, :class_name => "Log", :foreign_key => "target_id"
# 最后个回答
belongs_to :last_answer, :class_name => 'Answer'
# 最后回答者
belongs_to :last_answer_user, :class_name => 'User'
# Followers
references_and_referenced_in_many :followers, :stored_as => :array, :inverse_of => :followed_asks, :class_name => "User"
# Comments
has_many :comments, :conditions => {:commentable_type => "Ask"}, :foreign_key => "commentable_id", :class_name => "Comment"
has_many :ask_invites
attr_protected :user_id
attr_accessor :current_user_id
validates_presence_of :user_id, :title
validates_presence_of :current_user_id, :if => proc { |obj| obj.title_changed? or obj.body_changed? }
# 正常可显示的问题, 前台调用都带上这个过滤
scope :normal, where(:spams_count.lt => Setting.ask_spam_max)
scope :last_actived, desc(:answered_at)
scope :recent, desc("created_at")
# 除开一些 id,如用到 mute 的问题,传入用户的 muted_ask_ids
scope :exclude_ids, lambda { |id_array| not_in("_id" => (id_array ||= [])) }
scope :only_ids, lambda { |id_array| any_in("_id" => (id_array ||= [])) }
# 问我的问题
scope :asked_to, lambda { |to_user_id| where(:to_user_id => to_user_id) }
redis_search_index(:title_field => :title,
:score_field => :score,
:ext_fields => [:topics])
before_save :fill_default_values
after_create :create_log, :inc_counter_cache, :send_mails
after_destroy :dec_counter_cache
before_update :update_log
def view!
self.inc(:views_count, 1)
end
def score
self.comments_count + (self.answers_count * 3) + (self.follower_ids.count * 2)
end
def score_changed?
Rails.logger.debug "--- score_changed"
if self.comments_count_changed?
return true
end
if self.answers_count_changed?
return true
end
if self.follower_ids != self.follower_ids_was
return true
end
Rails.logger.debug "--- score_changed false #{self.follower_ids_was} --- #{self.follower_ids}"
false
end
def send_mails
# 向某人提问
if !self.to_user.blank?
if self.to_user.mail_ask_me
UserMailer.ask_user(self.id).deliver
end
end
end
def inc_counter_cache
self.user.inc(:asks_count, 1)
end
def dec_counter_cache
if self.user.asks_count > 0
self.user.inc(:asks_count, -1)
end
end
def update_log
insert_action_log("EDIT") if self.title_changed? or self.body_changed?
end
def create_log
insert_action_log("NEW")
end
# 敏感词验证
before_validation :check_spam_words
def check_spam_words
if self.spam?("title")
return false
end
if self.spam?("body")
return false
end
if self.spam?("topics")
return false
end
end
def chomp_body
if self.body == "<br>"
return ""
else
chomped = self.body
while chomped =~ /<div><br><\/div>$/i
chomped = chomped.gsub(/<div><br><\/div>$/i, "")
end
return chomped
end
end
def fill_default_values
# 默认回复时间为当前时间,已便于排序
if self.answered_at.blank?
self.answered_at = Time.now
end
end
# 更新话题
# 参数 topics 可以是数组或者字符串
# 参数 add true 增加, false 去掉
def update_topics(topics, add = true, current_user_id = nil)
self.topics = [] if self.topics.blank?
# 分割逗号
topics = topics.split(/,|,/) if topics.class != [].class
# 去两边空格
topics = topics.collect { |t| t.strip if !t.blank? }.compact
action = nil
if add
# 保存为独立的话题
new_topics = Topic.save_topics(topics, current_user_id)
self.topics += new_topics
action = "ADD_TOPIC"
else
self.topics -= topics
action = "DEL_TOPIC"
end
self.current_user_id = current_user_id
self.topics = self.topics.uniq { |s| s.downcase }
self.update(:topics => self.topics)
insert_topic_action_log(action, topics, current_user_id)
end
# 提交问题为 spam
def spam(voter_id,size = 1)
self.spams_count ||= 0
self.spam_voter_ids ||= []
# 限制 spam ,一人一次
return self.spams_count if self.spam_voter_ids.index(voter_id)
self.spams_count += size
self.spam_voter_ids << voter_id
self.current_user_id = "NULL"
self.save()
return self.spams_count
end
def self.search_title(text,options = {})
limit = options[:limit] || 10
Ask.search(text,:limit => limit)
end
def self.find_by_title(title)
first(:conditions => {:title => title})
end
# 重定向问题
def redirect_to_ask(to_id)
# 不能重定向自己
return -2 if to_id.to_s == self.id.to_s
@to_ask = Ask.find(to_id)
# 如果重定向目标的是重定向目前这个问题的,就跳过,防止无限重定向
return -1 if @to_ask.redirect_ask_id.to_s == self.id.to_s
self.redirect_ask_id = to_id
self.save
1
end
# 取消重定向
def redirect_cancel
self.redirect_ask_id = nil
self.save
end
protected
def insert_topic_action_log(action, topics, current_user_id)
begin
log = AskLog.new
log.user_id = current_user_id
log.title = topics.join(',')
log.ask = self
log.target_id = self.id
log.action = action
log.target_parent_id = self.id
log.target_parent_title = self.title
log.diff = ""
log.save
rescue Exception => e
end
end
def insert_action_log(action)
begin
log = AskLog.new
log.user_id = self.current_user_id
log.title = self.title
log.ask = self
log.target_id = self.id
log.target_attr = (self.title_changed? ? "TITLE" : (self.body_changed? ? "BODY" : "")) if action == "EDIT"
if(action == "NEW" and !self.to_user_id.blank?)
action = "NEW_TO_USER"
log.target_parent_id = self.to_user_id
end
log.action = action
log.diff = ""
log.save
rescue Exception => e
end
end
end