@@ -2,6 +2,7 @@ class UsersController < ApplicationController
22 include LocationFilters
33
44 CITY_SEARCH_DEFAULT_LIMIT = 5
5+ CITY_SEARCH_MAX_LIMIT = 20
56
67 before_action :authenticate_user!
78
@@ -38,13 +39,13 @@ def update
3839 court_preferences_submitted = user_params . key? ( :court_preferences_mode ) || user_params . key? ( :favorite_court_ids )
3940 court_preferences_mode = user_params [ :court_preferences_mode ] . presence || default_court_preferences_mode ( @user )
4041
41- query = user_attrs [ "city_name" ] . to_s . strip
42- if query . present?
43- coords_regex = / \A \s *-? \d +( \. \d +)? \s *, \s *-? \d +( \. \d +)? \s * \z /
44- # for plain names: transliterate immediately so DB shows e.g. "Kurgan"
45- unless query =~ coords_regex
46- user_attrs [ "city_name" ] = translit_str ( query )
47- end
42+ # Город принимаем только выбором из подсказок: произвольный текст в поле
43+ # раньше уезжал в city_name как есть и ломал матчинг с courts.city_name.
44+ user_attrs . delete ( "city_name" )
45+ selected_city = City . find_by ( id : params [ :selected_city_id ] ) if params [ :selected_city_id ] . present?
46+ if selected_city
47+ user_attrs [ "city_name" ] = selected_city . canonical_name
48+ user_attrs [ "timezone" ] = selected_city . rails_timezone if selected_city . rails_timezone . present?
4849 end
4950
5051 if court_preferences_submitted
@@ -63,12 +64,6 @@ def update
6364 Rails . logger . info "[UsersController#update] saving user_attrs=#{ user_attrs . inspect } "
6465
6566 if @user . update ( user_attrs )
66- # enqueue background job to resolve timezone asynchronously (by coords or by name)
67- if query . present?
68- ResolveUserCityJob . perform_later ( @user . id , query )
69- Rails . logger . info "[UsersController#update] enqueued ResolveUserCityJob for user_id=#{ @user . id } query=#{ query . inspect } "
70- end
71-
7267 respond_to do |format |
7368 format . html { redirect_to update_section_path ( section ) , notice : "Account updated" }
7469 format . json { render json : { success : true , city_name : @user . city_name , timezone : @user . timezone } }
@@ -95,6 +90,19 @@ def dismiss_onboarding
9590 redirect_back fallback_location : root_path
9691 end
9792
93+ # Подсказки для поля города: отдаём только то, что есть в справочнике, —
94+ # сохранить можно лишь выбранную строку.
95+ def city_search
96+ # Потолок обязателен: в SQLite отрицательный LIMIT снимает ограничение
97+ # совсем, и запрос вытащил бы весь справочник городов целиком.
98+ limit = params [ :limit ] . present? ? params [ :limit ] . to_i . clamp ( 1 , CITY_SEARCH_MAX_LIMIT ) : CITY_SEARCH_DEFAULT_LIMIT
99+ cities = Cities ::SearchService . new ( query : params [ :q ] , limit : limit ) . call
100+
101+ render json : cities . map { |city |
102+ { id : city . id , name : city . canonical_name , hint : [ city . country_code , city . timezone ] . compact_blank . join ( " · " ) }
103+ }
104+ end
105+
98106 def clear_city
99107 @user = current_user
100108 @user . update ( timezone : nil , city_name : nil )
@@ -177,10 +185,6 @@ def destroy
177185
178186 private
179187
180- def translit_str ( s )
181- Russian . translit ( s . to_s )
182- end
183-
184188 def user_update_params
185189 params . require ( :user ) . permit (
186190 :name ,
@@ -205,15 +209,15 @@ def prepare_notifications_form_state
205209 @registration_token = @user . ensure_telegram_registration_token!
206210 end
207211
212+ # Раньше здесь по таймзоне подбирался «какой-нибудь» город из справочника и
213+ # подставлялся в поле города. Таймзона города не определяет — в
214+ # Asia/Yekaterinburg лежит и Челябинск, и Тюмень, — поэтому не подставляем
215+ # ничего: пустое поле честнее угаданного.
208216 def prepare_profile_form_state
209- @limit = params [ :limit ] . to_i . nonzero? || CITY_SEARCH_DEFAULT_LIMIT
210-
211- if params [ :selected_city_name ] . present?
212- @selected_city_name = params [ :selected_city_name ]
213- else
214- c = City . find_by ( timezone : @user . timezone )
215- @selected_city_name = "#{ c . name } , #{ c . country_code } — #{ c . timezone } " if c . present?
216- end
217+ # После ошибки валидации форму рисуем заново, и выбранный город надо вернуть
218+ # в hidden-поле: в видимом поле он уже стоит, а без id следующая отправка
219+ # город не изменит.
220+ @selected_city_id = params [ :selected_city_id ] . presence
217221 end
218222
219223 def prepare_court_preferences_state
0 commit comments