• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MushroomObserver / mushroom-observer / 13610271121

02 Mar 2025 12:26AM UTC coverage: 93.562%. Remained the same
13610271121

push

github

nimmolo
Fix comment titling

1 of 1 new or added line in 1 file covered. (100.0%)

22 existing lines in 2 files now uncovered.

27366 of 29249 relevant lines covered (93.56%)

552.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.21
/app/controllers/comments_controller.rb
1
# frozen_string_literal: true
2

3
#  ==== Show, CRUD actions
4
#  index::
5
#  show::
6
#  new::
7
#  create::
8
#  edit::
9
#  update::
10
#  destroy::
11
#
12
class CommentsController < ApplicationController
1✔
13
  before_action :login_required
1✔
14
  before_action :pass_query_params, except: [:index]
1✔
15

16
  # Bullet doesn't seem to be able to figure out that we cannot eager load
17
  # through polymorphic relations, so I'm just disabling it for these actions.
18
  around_action :skip_bullet, if: -> { defined?(Bullet) }, only: [:index]
19✔
19

20
  ##############################################################################
21
  # INDEX
22
  #
23
  def index
1✔
24
    build_index_with_query
18✔
25
  end
26

27
  private
1✔
28

29
  def default_sort_order
1✔
30
    ::Query::Comments.default_order # :created_at
3✔
31
  end
32

33
  # ApplicationController uses this table to dispatch #index to a private method
34
  def index_active_params
1✔
35
    [:target, :pattern, :by_user, :for_user, :by].freeze
33✔
36
  end
37

38
  # Show selected list of comments, based on current Query.
39
  # (Linked from show_comment, next to "prev" and "next"... or will be.)
40
  # Passes explicit :by param to affect title (only).
41
  def sorted_index_opts
1✔
42
    sorted_by = params[:by] || default_sort_order
2✔
43
    super.merge(query_args: { by: sorted_by })
2✔
44
  end
45

46
  # Shows comments by a given user, most recent first. (Linked from show_user.)
47
  def by_user
1✔
48
    user = find_obj_or_goto_index(
4✔
49
      model: User, obj_id: params[:by_user].to_s,
50
      index_path: comments_path
51
    )
52
    return unless user
4✔
53

54
    query = create_query(:Comment, by_users: user)
3✔
55
    [query, {}]
3✔
56
  end
57

58
  # Shows comments for a given user's Observations, most recent first.
59
  # (Linked from show_user.)
60
  def for_user
1✔
61
    user = find_obj_or_goto_index(
4✔
62
      model: User, obj_id: params[:for_user].to_s,
63
      index_path: comments_path
64
    )
65
    return unless user
4✔
66

67
    query = create_query(:Comment, for_user: user)
3✔
68
    [query, {}]
3✔
69
  end
70

71
  # Shows comments for a given object, most recent first. (Linked from the
72
  # "and more..." thingy at the bottom of truncated embedded comment lists.)
73
  def target
1✔
74
    return no_model unless (model = Comment.safe_model_from_name(params[:type]))
4✔
75
    return unless (target = find_or_goto_index(model, params[:target].to_s))
2✔
76

77
    query = create_query(:Comment, target: { id: target.id,
2✔
78
                                             type: target.class.name })
79
    [query, {}]
2✔
80
  end
81

82
  def no_model
1✔
83
    flash_error(:runtime_invalid.t(type: '"type"', value: params[:type].to_s))
2✔
84
    redirect_back_or_default(action: :index)
2✔
85
    [nil, {}]
2✔
86
  end
87

88
  def index_display_opts(opts, query)
1✔
89
    opts = {
90
      num_per_page: 25,
13✔
91
      # (Eager-loading of names might fail when comments start to apply to
92
      # objects other than observations.)
93
      include: [:target, :user]
94
    }.merge(opts)
95

96
    # Paginate by letter if sorting by user.
97
    if (query.params[:by] == "user") || (query.params[:by] == "reverse_user")
13✔
98
      opts[:letters] = "users.login"
1✔
99
    end
100

101
    @full_detail = query.params[:for_target].present?
13✔
102

103
    opts
13✔
104
  end
105

106
  public
1✔
107

108
  ##############################################################################
109
  #
110
  #  :section: Show
111
  #
112
  ##############################################################################
113

114
  # Display comment by itself.
115
  # Linked from: show_<object>, index
116
  # Inputs: params[:id] (comment)
117
  # Outputs: @comment, @object
118
  def show
1✔
119
    store_location
1✔
120
    return unless (@comment = find_comment!)
1✔
121

122
    case params[:flow]
1✔
123
    when "next"
UNCOV
124
      redirect_to_next_object(:next, Comment, params[:id]) and return
×
125
    when "prev"
UNCOV
126
      redirect_to_next_object(:prev, Comment, params[:id]) and return
×
127
    end
128

129
    @target = @comment.target
1✔
130
    allowed_to_see!(@target)
1✔
131
  end
132

133
  private
1✔
134

135
  def find_comment!
1✔
136
    find_or_goto_index(Comment, params[:id].to_s)
7✔
137
  end
138

139
  # Make sure users can't see/add comments on objects they aren't allowed to
140
  # view!  Redirect and return +false+ if they can't, else return +true+.
141
  def allowed_to_see!(object)
1✔
142
    return true unless object.respond_to?(:is_reader?) &&
12✔
143
                       !object.is_reader?(@user) &&
144
                       !in_admin_mode?
145

146
    flash_error(:runtime_show_description_denied.t)
1✔
147
    parent = object.parent
1✔
148
    redirect_to(controller: parent.show_controller,
1✔
149
                action: parent.show_action, id: parent.id)
150
    false
1✔
151
  end
152

153
  public
1✔
154

155
  ##############################################################################
156
  #
157
  #  :section: CRUD actions
158
  #
159
  ##############################################################################
160

161
  # Form to create comment for an object.
162
  # Linked from: show_<object>
163
  # Inputs:
164
  #   params[:id] (object id)
165
  #   params[:type] (object type)
166
  #   params[:comment][:summary]
167
  #   params[:comment][:comment]
168
  # Success:
169
  #   Redirects to show_<object>.
170
  # Failure:
171
  #   Renders add_comment again.
172
  #   Outputs: @comment, @object
173
  def new
1✔
174
    return unless (@target = load_target(params[:type], params[:target])) &&
6✔
175
                  allowed_to_see!(@target)
176

177
    @comment = Comment.new(target: @target)
4✔
178

179
    respond_to do |format|
4✔
180
      format.html
4✔
181
      format.turbo_stream { render_modal_comment_form }
4✔
182
    end
183
  end
184

185
  def create
1✔
186
    return unless (@target = load_target(params[:type], params[:target])) &&
2✔
187
                  allowed_to_see!(@target)
188

189
    @comment = Comment.new(target: @target)
2✔
190
    @comment.attributes = permitted_comment_params if params[:comment]
2✔
191

192
    unless @comment.save
2✔
193
      flash_object_errors(@comment)
×
UNCOV
194
      reload_form and return
×
195
    end
196

197
    @comment.log_create
2✔
198
    flash_notice(:runtime_form_comments_create_success.t(id: @comment.id))
2✔
199

200
    refresh_comments_or_redirect_to_show
2✔
201
  end
202

203
  # Form to edit a comment for an object..
204
  # Linked from: show_comment, show_object.
205
  # Inputs:
206
  #   params[:id]
207
  #   params[:comment][:summary]
208
  #   params[:comment][:comment]
209
  # Success:
210
  #   Redirects to show_object.
211
  # Failure:
212
  #   Renders edit_comment again.
213
  #   Outputs: @comment, @object
214
  def edit
1✔
215
    return unless (@comment = find_comment!)
2✔
216

217
    @target = comment_target
2✔
218
    return unless allowed_to_see!(@target)
2✔
219
    return unless check_permission_or_redirect!(@comment, @target)
2✔
220

221
    respond_to do |format|
1✔
222
      format.turbo_stream { render_modal_comment_form }
1✔
223
      format.html
1✔
224
    end
225
  end
226

227
  def update
1✔
228
    return unless (@comment = find_comment!)
2✔
229

230
    @target = comment_target
2✔
231
    return unless allowed_to_see!(@target) &&
2✔
232
                  check_permission_or_redirect!(@comment, @target)
233

234
    @comment.attributes = permitted_comment_params if params[:comment]
1✔
235
    reload_form and return unless comment_updated?
1✔
236

237
    refresh_comments_or_redirect_to_show
1✔
238
  end
239

240
  # Callback to destroy a comment.
241
  # Linked from: show_comment, show_object.
242
  # Redirects to show_object.
243
  # Inputs: params[:id]
244
  # Outputs: none
245
  def destroy
1✔
246
    return unless (@comment = find_comment!)
2✔
247

248
    @target = @comment.target
2✔
249
    if !check_permission!(@comment)
2✔
250
      # all html requests redirect to object show page
251
    elsif !@comment.destroy
1✔
UNCOV
252
      flash_error(:runtime_form_comments_destroy_failed.t(id: params[:id]))
×
253
    else
254
      @comment.log_destroy
1✔
255
      flash_notice(:runtime_form_comments_destroy_success.t(id: params[:id]))
1✔
256
    end
257

258
    respond_to do |format|
2✔
259
      # format.turbo_stream do
260
      # helpers.render_turbo_stream_flash_messages
261
      # end
262
      format.html do
2✔
263
        redirect_with_query(controller: @target.show_controller,
2✔
264
                            action: @target.show_action, id: @target.id)
265
      end
266
    end
267
  end
268

269
  private
1✔
270

271
  # The identifier needs to be more specific for an edit form, because
272
  # we give users the option to edit any number of their own comments on a
273
  # show page. "comment" disambiguates :new, because :edit always has id
274
  def render_modal_comment_form
1✔
UNCOV
275
    render(partial: "shared/modal_form",
×
276
           locals: { title: modal_title, identifier: modal_identifier,
277
                     form: "comments/form" }) and return
278
  end
279

280
  def reload_modal_form
1✔
UNCOV
281
    render(partial: "shared/modal_form_reload",
×
282
           locals: { identifier: modal_identifier,
283
                     form: "comments/form" })
284
  end
285

286
  def modal_identifier
1✔
UNCOV
287
    case action_name
×
288
    when "new", "create"
UNCOV
289
      "comment"
×
290
    when "edit", "update"
UNCOV
291
      "comment_#{@comment.id}"
×
292
    end
293
  end
294

295
  def modal_title
1✔
UNCOV
296
    case action_name
×
297
    when "new", "create"
UNCOV
298
      helpers.comment_form_new_title(target: @target)
×
299
    when "edit", "update"
UNCOV
300
      helpers.comment_form_edit_title(target: @target)
×
301
    end
302
  end
303

304
  def permitted_comment_params
1✔
305
    params[:comment].permit([:summary, :comment])
3✔
306
  end
307

308
  def reload_form
1✔
309
    respond_to do |format|
×
310
      format.turbo_stream { reload_modal_form }
×
UNCOV
311
      format.html { render(:new) }
×
312
    end
313
  end
314

315
  def refresh_comments_or_redirect_to_show
1✔
316
    # Comment broadcasts are sent from the model
317
    respond_to do |format|
3✔
318
      # format.turbo_stream do
319
      # helpers.render_turbo_stream_flash_messages
320
      # end
321
      format.html do
3✔
322
        redirect_with_query(controller: @target.show_controller,
3✔
323
                            action: @target.show_action, id: @target.id)
324
      end
325
    end
326
  end
327

328
  def comment_target
1✔
329
    load_target(@comment.target_type, @comment.target_id)
4✔
330
  end
331

332
  def load_target(type, id)
1✔
333
    case type
12✔
334
    when "Observation"
335
      load_for_show_observation_or_goto_index(id)
6✔
336
    else
337
      target = Comment.find_object(type, id.to_s)
6✔
338
      redirect_back_or_default("/") unless target
6✔
339
      target
6✔
340
    end
341
  end
342

343
  def check_permission_or_redirect!(comment, target)
1✔
344
    return true if check_permission!(comment)
4✔
345

346
    redirect_with_query(controller: target.show_controller,
2✔
347
                        action: target.show_action, id: target.id)
348
    false
2✔
349
  end
350

351
  def comment_updated?
1✔
352
    if !@comment.changed?
1✔
UNCOV
353
      flash_notice(:runtime_no_changes.t)
×
354
      # changing this to `false`, because comment has not been changed.
355
      # Flash should render in modal (the `false` path) - AN 20231201
UNCOV
356
      false
×
357
    elsif !@comment.save
1✔
358
      flash_object_errors(@comment)
×
UNCOV
359
      false
×
360
    else
361
      @comment.log_update
1✔
362
      flash_notice(:runtime_form_comments_edit_success.t(id: @comment.id))
1✔
363
      true
1✔
364
    end
365
  end
366
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc