Class: SearchesController

Inherits:
CrmController show all
Defined in:
app/controllers/searches_controller.rb

Overview

Controller: searches.

Constant Summary

Constants included from Controllers::ReferenceFindable

Controllers::ReferenceFindable::ID_EMBEDDED_PATTERNS

Constants included from Controllers::AnalyticsEvents

Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY

Constants included from Controllers::ErrorRendering

Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES

Constants included from Www::SeoHelper

Www::SeoHelper::AWARDS, Www::SeoHelper::CA_ADDRESS, Www::SeoHelper::CA_BUSINESS_HOURS, Www::SeoHelper::CA_CONTACT_POINT, Www::SeoHelper::CA_CURRENCIES, Www::SeoHelper::CA_DESCRIPTION, Www::SeoHelper::CA_FOUNDING_DATE, Www::SeoHelper::CA_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::CA_LEGAL_NAME, Www::SeoHelper::CA_LOCAL_BUSINESS, Www::SeoHelper::CA_ONLINE_STORE, Www::SeoHelper::CA_RETURN_POLICY, Www::SeoHelper::CA_SALES_DEPARTMENT, Www::SeoHelper::CA_SERVICE_AREA, Www::SeoHelper::CA_URL, Www::SeoHelper::CA_VAT_ID, Www::SeoHelper::CA_WAREHOUSE_DEPARTMENT, Www::SeoHelper::CA_WAREHOUSE_HOURS, Www::SeoHelper::COMPANY_EMAIL, Www::SeoHelper::COMPANY_LOGO, Www::SeoHelper::COMPANY_NAME, Www::SeoHelper::COMPANY_SLOGAN, Www::SeoHelper::EXPERTISE, Www::SeoHelper::FAX_NUMBER, Www::SeoHelper::GS1_COMPANY_PREFIX, Www::SeoHelper::ISO6523_CODE, Www::SeoHelper::PAYMENT_METHODS, Www::SeoHelper::PHONE_NUMBER, Www::SeoHelper::PRIMARY_NAICS, Www::SeoHelper::REFUND_TYPE, Www::SeoHelper::RETURN_FEES, Www::SeoHelper::RETURN_METHOD, Www::SeoHelper::RETURN_POLICY_CATEGORY, Www::SeoHelper::SECONDARY_NAICS, Www::SeoHelper::SOCIAL_PROFILES, Www::SeoHelper::US_ADDRESS, Www::SeoHelper::US_BUSINESS_HOURS, Www::SeoHelper::US_CONTACT_POINT, Www::SeoHelper::US_CURRENCIES, Www::SeoHelper::US_DESCRIPTION, Www::SeoHelper::US_FOUNDING_DATE, Www::SeoHelper::US_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::US_IMAGE, Www::SeoHelper::US_LEGAL_NAME, Www::SeoHelper::US_LOCAL_BUSINESS, Www::SeoHelper::US_ONLINE_STORE, Www::SeoHelper::US_RETURN_POLICY, Www::SeoHelper::US_SALES_DEPARTMENT, Www::SeoHelper::US_SERVICE_AREA, Www::SeoHelper::US_TAX_ID, Www::SeoHelper::US_URL, Www::SeoHelper::US_WAREHOUSE_DEPARTMENT, Www::SeoHelper::US_WAREHOUSE_HOURS

Constants included from IconHelper

IconHelper::CUSTOM_ICON_MAP, IconHelper::CUSTOM_SVG_DIR, IconHelper::DEFAULT_FAMILY

Instance Method Summary collapse

Methods inherited from CrmController

#access_denied, #context_id, #context_object, #crm_home_path, #current_ability, #default_url_options, #download_temp, #get_tempfile_path_for_download, #init_status_job_collector, #initialize_crm_lazy_chunks, #persist_enqueued_status_jobs, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download, #sync_admin_presence_cookie

Methods inherited from ApplicationController

#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #stamp_impersonation_context, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y

Methods included from Controllers::ReturnPathHandling

#check_for_return_path, #redirect_to_return_path_or_default

Methods included from Controllers::AnalyticsEvents

#consume_queued_analytics_events, #track_event

Methods included from Controllers::DeviceDetection

#device_detector, #is_ie?

Methods included from Controllers::SubdomainDetection

#is_crm_request?, #is_www_request?, #json_request?

Methods included from Controllers::TurboSafeRedirect

#redirect_to

Methods included from Controllers::TrackingDetection

#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?

Methods included from Controllers::AcceleratedFileSending

#send_file_accelerated, #send_upload_accelerated

Methods included from Controllers::ErrorRendering

#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback

Methods included from Controllers::TurnstileVerification

#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!

Methods included from Controllers::CloudflareCaching

edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session

Methods included from Controllers::Webpackable

#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?

Methods included from Controllers::Localizable

#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale

Methods included from Controllers::Authenticable

#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak

Methods included from ApplicationHelper

#better_number_to_currency, #check_force_logout, #check_or_cross, #check_or_times, #embedded_tab_frame_id, #error_messages, #general_disclaimer_on_product_installation_and_local_codes, #gridjs_from_html_table, #gridjs_table, #is_wy_ip, #line_break, #parent_layout, #pass_or_fail, #render_error_messages_list, #render_video_card, #resolved_auth_form_turbo_frame, #return_path_or, #safe_css_color, #set_return_path_if_present, #set_section_if_present, #tab_frame_id, #to_underscore, #track_page?, #turbo_section_wrapper, #turbo_tabs_request?, #url_on_same_domain_as_request, #widget_index_daily_focus_index_path, #working_hours?, #yes_or_no, #yes_or_no_highlighted, #yes_or_no_with_check_or_cross, #youtube_video

Methods included from UppyUploaderHelper

#file_uploader, #image_uploader, #large_file_uploader_s3, #lead_sketch_uploader, #rma_image_uploader, #rma_image_uploader_s3, #uppy_uploader, #video_uploader

Methods included from Www::ImagesHelper

#image_asset_tag, #image_asset_url

Methods included from Www::SeoHelper

#add_page_schema, #add_webpage_schema, #canada?, #company_social_links, #ensure_context_json, #json_ld_script_tag, #local_business_schema, #online_store_id, #online_store_schema, #page_main_entity, #page_main_entity_json, #render_auto_collection_page_schema, #render_collection_page_schema, #render_local_business_schema, #render_online_store_schema, #render_page_schemas, #render_page_video_schemas, #render_webpage_schema, #render_webpage_schema_with_collections, #usa?

Methods included from UrlsHelper

#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?

Methods included from IconHelper

#account_nav_icon, #fa_icon, #star_rating_html

Instance Method Details

#advanced_search_panelObject

Lazy-loaded body for the navbar's Advanced Search offcanvas. The navbar
renders an empty <turbo-frame id="advancedSearchOffcanvasFrame"> shell;
crm-navbar Stimulus sets the frame's src to this action on every
show.bs.offcanvas, so the per-type recent-search and template queries
only run when the user actually opens the panel.

expires_in 15.seconds, public: false lets the user's browser cache
the response for rapid re-opens (matches the lazy navbar dropdown
bodies) while keeping responses out of any shared cache. Per-user
data, so private is mandatory.



35
36
37
38
# File 'app/controllers/searches_controller.rb', line 35

def advanced_search_panel
  expires_in 15.seconds, public: false
  render partial: 'advanced_search_offcanvas_body', layout: false
end

#createObject



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
# File 'app/controllers/searches_controller.rb', line 88

def create
  template_key = params[:template_key] || :default
  p = search_class.try(:global_favorites).try(:dig, template_key) || {}
  p = p.slice(:query_params, :sort_columns)
  p = p.deep_merge(params[:search].to_h)
  @search = search_class.new(p)

  @search.employee_id = employee.id
  authorize! :create, @search
  if @search.save
    if @search.pinned
      @search.perform(1, nil, nil, true)
      redir_url = get_first_search_result_link
      if redir_url
        flash[:info] = 'Search results were automatically pinned'
        redirect_to redir_url
      else
        redirect_to search_path(@search)
      end
    elsif params[:edit].present?
      redirect_to edit_search_path(@search)
    else
      redirect_to search_path(@search)
    end
  else
    render :new, status: :unprocessable_content
  end
end

#create_onboarding_packetObject



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'app/controllers/searches_controller.rb', line 322

def create_onboarding_packet
  require 'zip'
  @search = Search.find(params[:id])
  zip_name = "onboarding_#{@search.id}.zip"
  directory_path = Rails.root.join(Rails.application.config.x.temp_storage_path.to_s, 'users', current_user ? current_user.id.to_s : '')
  FileUtils.mkdir_p(directory_path)
  zip_path = Rails.root.join(directory_path, zip_name)

  Zip::File.open(zip_path, create: true) do |zipfile|
    file_name = "onboarding_#{@search.id}#{"_#{zipfile.size}" if zipfile.size.positive?}.csv"
    file_path = Rails.root.join(directory_path, file_name)
    CSV.open(file_path, 'w', force_quotes: true, encoding: 'WINDOWS-1252') do |csv|
      csv << ['item_name', 'item_sku', 'product_category', 'brand_name', 'collection', 'UPC', 'product_weight',
              'product_height', 'product_width', 'product_depth', 'shipping_weight', 'shipping_height', 'shipping_width',
              'shipping_depth', 'shipping_type', 'product_description', 'bullet_point_1', 'bullet_point_2', 'bullet_point_3', 'bullet_point_4',
              'bullet_point_5', 'country_of_origin', 'Length', 'Amps', 'Weight', 'Width', 'Voltage', 'Heating Wire', 'Floor Types',
              'Approvals', 'Watts', 'BTU per Hour', 'Heated Area']

      @search.search_results.each do |result|
        row = []
        catalog_item = result.resource
        item = catalog_item.item
        row.push(item.name, item.sku, item.brand_id.equal?(1) ? 'WarmlyYours USA' : 'WarmlyYours CA', 'collection',
                 item.upc, item.base_weight, 'product_height', item.width, 'product_depth', item.shipping_weight, item.shipping_height,
                 item.shipping_width, 'shipping_depth', 'shipping_type',
                 item.detailed_description.presence || catalog_item.primary_product_line.description,
                 'bullet_point_1', 'bullet_point_2', 'bullet_point_3', 'bullet_point_4', 'bullet_point_5', item.coo)
        item.product_specifications.each do |spec|
          row << spec.get_specification_data(catalog_item).formatted
        end
        csv << row
      end
    end
    zipfile.add(file_name, file_path)
  end

  session[:download_path] = "/tempfile/#{zip_name}"
  flash[:info] = "File created <br><a href='#{session[:download_path]}' class='btn btn-outline-primary'>Download</a>"
  redirect_back_or_to(root_path)
end

#destroyObject



379
380
381
382
383
# File 'app/controllers/searches_controller.rb', line 379

def destroy
  @search = @context_user.searches.find(params[:id])
  flash[:info] = "Search id #{@search.id} deleted." if @search.destroy
  redirect_to_return_path_or_default employee_searches_path(@context_user, type: @search.class.name)
end

#editObject



84
85
86
# File 'app/controllers/searches_controller.rb', line 84

def edit
  @search = Search.find(params[:id])
end


212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'app/controllers/searches_controller.rb', line 212

def get_first_search_result_link
  return unless (first_resource = @search.search_results.first&.resource)

  begin
    first_resource.crm_link
  rescue StandardError
    nil
  end || begin
    polymorphic_path(first_resource)
  rescue StandardError
    nil
  end
end

#indexObject



8
9
10
11
12
13
14
15
# File 'app/controllers/searches_controller.rb', line 8

def index
  if params[:type].present?
    search_class # sets the search class
    @searches = employee.searches.where(type: params[:type]).order(created_at: :desc)
  else
    redirect_to(search_types_searches_path)
  end
end

#mass_actionObject



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'app/controllers/searches_controller.rb', line 285

def mass_action
  expires_now
  @search = Search.find(params[:id])
  @mass_action_type = params[:mass_action_type]
  if @search.search_results.empty?
    redirect_to search_path(@search), flash: { error: 'You must select some records before performing a mass action.' }
  elsif @mass_action_type.blank? || !@search.respond_to?(@mass_action_type)
    redirect_to search_path(@search), flash: { error: 'You must select a valid mass action to perform.' }
  else
    # Try to find if a partial is present to render a pre-execution form to capture params or an action to perform directly
    @mass_action = OpenStruct.new(params[:mass_action].to_h)
    view_root_path = Rails.root.join('app/views/searches')
    # Is there a search model specific view for this mass action?
    if File.exist?(view_root_path.join(@search.class.name.underscore, "_#{@mass_action_type}.html.erb"))
      @mass_action_partial_path = "/searches/#{@search.class.name.underscore}/#{@mass_action_type}"
    # Is there a generalized search view?
    elsif File.exist?(view_root_path.join("_#{@mass_action_type}.html.erb"))
      @mass_action_partial_path = "/searches/#{@mass_action_type}"
    # execute mass action directly
    else
      @search.send(@mass_action_type.to_sym, self)
    end
  end
end

#newObject



71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/controllers/searches_controller.rb', line 71

def new
  template_key = params[:template_key] || :default
  p = search_class.try(:global_favorites).try(:dig, template_key) || {}
  p = p.slice(:query_params, :sort_columns)
  p = p.deep_merge(params[:search] || {})
  p[:set_limit] ||= 50
  p[:employee] ||= employee
  p[:query_params] = params[:query_params]&.to_h.presence || p[:query_params] || {}
  @search = search_class.new(p)
  @search.set_defaults
  authorize! :create, @search
end

#onboarding_packetObject



310
311
312
313
314
315
316
317
318
319
320
# File 'app/controllers/searches_controller.rb', line 310

def onboarding_packet
  @search = Search.find(params[:id])
  # @search.search_results.each do |result|
  #   catalog_item = result.resource
  #   item = catalog_item.item
  #
  # end
  respond_to do |format|
    format.html
  end
end

#perform_mass_actionObject



363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'app/controllers/searches_controller.rb', line 363

def perform_mass_action
  mass_action_params = params[:mass_action].to_h.deep_squish.with_indifferent_access
  @search      = Search.find(params[:id])
  @mass_action = params[:mass_action_type]

  unless @mass_action.present? && @search.respond_to?(@mass_action)
    flash[:error] = "Mass action #{params[:mass_action]} not recognized"
    redirect_to search_path(@search) and return
  end

  # Every mass action method now owns its own background execution by enqueuing
  # a worker and returning { job_id: }. The controller always calls the method
  # directly and routes based on the response type.
  run_mass_action_synchronously(mass_action_params)
end

#pinObject



233
234
235
236
237
238
239
240
241
# File 'app/controllers/searches_controller.rb', line 233

def pin
  @search = Search.find(params[:id])
  if @search.search_results.present?
    mark_pinned_and_redirect
  else
    flash[:error] = 'Your search has no results that can be pinned.  Select records before attempting pinning.'
    redirect_to search_path(@search)
  end
end

#pin_allObject



226
227
228
229
230
231
# File 'app/controllers/searches_controller.rb', line 226

def pin_all
  @search = Search.find(params[:id])
  @search.record_list('*')
  @search.update_attribute!(:pinned, true)
  mark_pinned_and_redirect
end

#pinned_resultsObject



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'app/controllers/searches_controller.rb', line 243

def pinned_results
  results = {}
  @search = Search.where(employee_id: params[:employee_id]).where(pinned: true).first
  @context_type = params[:context_type]
  @context_id = params[:context_id]
  @current_path = params[:current_path]
  if @search
    @pagy, @results = pagy(@search.get_pinned_results, limit: 20)
    results[:status] = :ok
    results[:results] = @results
  else
    results[:status] = :not_found
  end

  respond_to do |format|
    format.turbo_stream
    format.json { render json: results }
    format.html { render layout: false }
  end
end

#recordObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/controllers/searches_controller.rb', line 132

def record
  @search = Search.find(params[:id])
  check_list_ids = params[:check_list_ids]
  uncheck_list_ids = params[:uncheck_list_ids]

  @search.record_list(check_list_ids)
  @search.unrecord_list(uncheck_list_ids)

  respond_to do |format|
    # Primary client path: render the mass-action button (counter +
    # dropdown items) server-side. The server knows the post-update
    # selected count and total_count, so it renders the right state
    # without any client-side sync logic.
    format.turbo_stream do
      render turbo_stream: turbo_stream.replace("mass-action-button-#{@search.id}", partial: 'searches/search_actions')
    end
    # Kept for any non-browser caller.
    format.json { render json: { status: :ok, selected: @search.search_results.count, checked: check_list_ids, unchecked: uncheck_list_ids } }
  end
end

#refresh_pinnedObject

Prunes the user's pinned set against current data: keeps only the records
that still match the saved criteria (e.g. drops an opportunity that was
closed and no longer satisfies an "open" filter). Never auto-adds new
rows — pinning is a curated subset and we respect that. Mutating action —
POST only, and restricted to the current user's own pinned search.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'app/controllers/searches_controller.rb', line 269

def refresh_pinned
  head :forbidden and return unless current_user.id.to_s == params[:employee_id].to_s

  @search = Search.where(employee_id: current_user.id, pinned: true).first
  @current_path = params[:current_path]

  if @search
    @search.refresh_pinned_results
    @pagy, @results = pagy(@search.get_pinned_results, limit: 20)
  end

  respond_to do |format|
    format.turbo_stream { render :pinned_results }
  end
end

#resetObject



117
118
119
120
121
122
# File 'app/controllers/searches_controller.rb', line 117

def reset
  @search = Search.find(params[:id])
  @search.query_params = nil
  @search.save
  redirect_to search_path(@search)
end

#search_and_pinObject

Executes a search and pin in one shot



199
200
201
202
203
204
205
206
207
208
209
210
# File 'app/controllers/searches_controller.rb', line 199

def search_and_pin
  @search = params[:id].present? ? Search.find(params[:id]) : search_class.new(params[:search])
  @search.employee_id = employee.id
  @search.pinned = true
  if @search.save
    @search.perform(1, nil, nil, true) # True stores the pinned search
    @results = @search.pinned_query
  end
  respond_to do |format|
    format.turbo_stream
  end
end

#search_and_showObject



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
# File 'app/controllers/searches_controller.rb', line 162

def search_and_show
  @search = search_class.new(set_limit: params[:set_limit] || 50, employee: @context_user, query_params: params[:query_params].to_h.presence || {},
                             selected_columns: params[:selected_columns], sort_columns: params[:sort_columns])
  @links = params[:links] || {}
  @target_id = params[:target_id] || 'search_and_show'
  action_view = params[:search_mode] == 'full' ? 'show' : 'search_and_show'
  unless @search.save
    # Search criteria failed validation: surface the error rather than
    # returning an empty 200 (which Turbo silently discards).
    flash.now[:error] = "Search could not be saved: #{@search.errors_to_s}"
    respond_to do |format|
      format.html { render plain: flash.now[:error], status: :unprocessable_content }
      format.turbo_stream { render partial: 'shared/flash', status: :unprocessable_content }
    end
    return
  end

  # Perform paginated query; Search will expose Pagy via pagy_from_search
  page = (params[:page] || 1).to_i
  # Pagy uses params[:items] for per-page count, fall back to saved set_limit
  per_page = params[:items].presence || @search.set_limit
  @results = @search.perform(page, params[:sort], params[:direction], false, per_page, true, false)
  # Create Pagy object with request context for URL generation
  if @search.pagy_from_search
    @pagy = pagy(:offset, @results,
                 count: @search.pagy_from_search.count,
                 page: @search.pagy_from_search.page,
                 limit: @search.pagy_from_search.limit)[0]
  end

  respond_to do |format|
    format.html { render action: action_view, layout: should_render_layout? }
    format.turbo_stream
  end
end

#search_typesObject



17
18
19
20
21
22
23
# File 'app/controllers/searches_controller.rb', line 17

def search_types
  @search_types = Search.options
  # `should_render_layout?` keeps the response usable both as a real page
  # (e.g. when SearchesController#index redirects here with no `:type`)
  # and as a turbo-frame fragment.
  render layout: should_render_layout?
end

#showObject



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
# File 'app/controllers/searches_controller.rb', line 40

def show
  @search = Search.find(params[:id])
  authorize! :read, @search

  begin
    # Ask the search to return the current page; it will set result_set_size and pagy_from_search
    page = (params[:page] || 1).to_i
    # Pagy uses params[:items] for per-page count, fall back to saved set_limit
    per_page = params[:items].presence || @search.set_limit
    @results = @search.perform(page, params[:sort], params[:direction], false, per_page, true, false)
    # Create Pagy object with request context for URL generation
    if @search.pagy_from_search
      @pagy = pagy(:offset, @results,
                   count: @search.pagy_from_search.count,
                   page: @search.pagy_from_search.page,
                   limit: @search.pagy_from_search.limit)[0]
    end
  rescue StandardError => e
    Rails.logger.error "[SearchesController#show] perform failed for Search##{@search.id} (#{@search.type}): #{e.class}#{e.message}"
    Appsignal.report_error(e) do |transaction|
      transaction.set_tags(search_id: @search.id.to_s, search_type: @search.type)
    end
    @pagy = nil
    @results = []
  end

  respond_to do |format|
    format.html
  end
end

#unpinObject



124
125
126
127
128
129
130
# File 'app/controllers/searches_controller.rb', line 124

def unpin
  @search_result_id = params[:search_result_id]
  @search_results = SearchResult.destroy_by(id: @search_result_id)
  respond_to do |format|
    format.turbo_stream
  end
end

#updateObject



153
154
155
156
157
158
159
160
# File 'app/controllers/searches_controller.rb', line 153

def update
  @search = Search.find(params[:id])
  if @search.update(params[:search])
    redirect_to search_path(@search)
  else
    render :edit, status: :unprocessable_content
  end
end