Class: Review

Inherits:
ApplicationRecord show all
Extended by:
Enumerize, FriendlyId
Includes:
IdentityCache
Defined in:
app/models/review.rb

Overview

Review Model

Constant Summary collapse

'hungryhub://reservationsRating/%<reservation_id>s/push'
'hungryhub://reservationsRating/%<reservation_id>s'
AVAILABLE_OCCASIONS =
%i[everyday_dining date business_meal meetup_with_friends anniversary birthday
other_occasion].freeze
AVAILABLE_RECOMMENDATIONS =
%i[solo_dining friends couple business family special_occasion other].freeze
RECOMMENDATION_TEXT_FIELDS =

Fields that supplement recommendations (not dimension identifiers)

%i[other_text].freeze
AVAILABLE_RATINGS =
%i[food ambience service value delivery_service packaging social_distancing overall_cleanliness
staff_protection].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

sync_carrierwave_url

Class Method Details



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'app/models/review.rb', line 205

def self.featured_reviews(limit = 15)
  Rails.cache.fetch("Review|FeaturedReviews|#{MyLocaleManager.normalize_locale}",
                    expires_in: CACHEFLOW.generate_expiry) do
    sql = <<~SQL
      SELECT `reviews`.* FROM `reviews`
      INNER JOIN `reservations` ON `reservations`.`id` = `reviews`.`reservation_id`
      INNER JOIN `restaurants` ON `restaurants`.`id` = `reservations`.`restaurant_id`
      WHERE `reviews`.`rating` = 5
      AND (`reviews`.`review` IS NOT NULL AND trim(coalesce(`reviews`.`review`, '')) <> '')
      AND `restaurants`.`active` = 1
      ORDER BY reviews.id DESC
      LIMIT #{limit}
    SQL
    Review.find_by_sql sql
  end
end

.rate_able_reservation(user_id) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'app/models/review.rb', line 222

def self.rate_able_reservation(user_id)
  user = User.find(user_id)
  reservation_ids = user.reviews.select(&:can_be_rated?).map(&:reservation_id)
  reservation_ids += user.reservations.map(&:review).
    select(&:can_be_rated?).map(&:reservation_id)
  reservation_ids.uniq!

  if reservation_ids.present?
    Reservation.unscoped.where("id IN (#{reservation_ids.join(',')})").
      where(active: true, no_show: false).order('id DESC')
  else
    rated_reservations = user.reviews.pluck(:reservation_id)
    query = Reservation.includes(:restaurant).all
    query = query.where("id NOT IN (#{rated_reservations.join(',')})") if rated_reservations.present?
    query.where(user_id: user.id).where(active: true, no_show: false).order('id DESC')
  end
end

Instance Method Details

#can_be_rated?Bool

Returns:

  • (Bool)


189
190
191
192
193
194
195
196
197
198
199
# File 'app/models/review.rb', line 189

def can_be_rated?
  now = Time.use_zone(reservation.restaurant&.time_zone || HungryHub::Time::DEFAULT_ZONE) do
    Time.zone.now
  end

  return true if delayed_time_has_passed? && state < 3 &&
    reservation.active? && !reservation.read_attribute(:no_show) &&
    now < (reservation.reservation_time + 30.days)

  false
end

#disclose_review?Boolean

Returns:

  • (Boolean)


248
249
250
251
252
253
254
255
256
257
258
# File 'app/models/review.rb', line 248

def disclose_review?
  sc = if user_id.present?
         SharedCustomer.find_by(user_id: user_id, reservation_id: reservation_id)
       elsif reservation_id.present?
         SharedCustomer.find_by(reservation_id: reservation_id)
       end

  return sc.disclose_review if sc.present?

  true
end


201
202
203
# File 'app/models/review.rb', line 201

def link
  ::HungryHub::Reservation::Codec.encode(reservation_id)
end

#occasion_titleString

Returns the localized, human-readable title for the review's occasion.

This method looks up the translation for the current review's `occasion` attribute using the I18n system and returns it in titleized form. If the occasion is blank or not included in the list of available occasions, it returns an empty string.

If an error occurs during translation (e.g., missing translation key), the error is reported to the APM system via APMErrorHandler, and an empty string is returned.

Returns:

  • (String)

    The localized and titleized occasion name, or empty string if not available or on error.



311
312
313
314
315
316
317
318
319
320
321
# File 'app/models/review.rb', line 311

def occasion_title
  return '' if occasion.blank?
  return '' unless AVAILABLE_OCCASIONS.include?(occasion.to_sym)

  I18n.t("views.review.occasion_type.#{occasion}").titleize
rescue StandardError
  APMErrorHandler.report(
    "#{self.class} Error translating occasion type '#{occasion}' for Review ID: #{id}",
  )
  ''
end

#ours?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'app/models/review.rb', line 165

def ours?
  true # we don't use Foursquare data anymore
end

#rating_typesObject



290
291
292
293
294
295
296
297
298
# File 'app/models/review.rb', line 290

def rating_types
  return [] unless reservation&.service_type.present?

  if reservation.service_type == 'dine_in'
    %w(food ambience service value)
  else
    %w(food value packaging delivery_service)
  end
end

#recommendation_title_for(identifier) ⇒ String

Returns the localized, human-readable title for a given recommendation identifier.

This method accepts an identifier (symbol or string) representing a recommendation type (e.g., :friends, :family) and returns the corresponding translation in titleized form. If the identifier is blank or not included in the list of available recommendations, it returns an empty string.

If an error occurs during translation (e.g., missing translation key), the error is reported to the APM system via APMErrorHandler, and an empty string is returned.

Parameters:

  • identifier (String, Symbol)

    The recommendation identifier to translate.

Returns:

  • (String)

    The localized and titleized recommendation name, or empty string if not available or on error.



336
337
338
339
340
341
342
343
344
345
346
# File 'app/models/review.rb', line 336

def recommendation_title_for(identifier)
  return '' if identifier.blank?
  return '' unless AVAILABLE_RECOMMENDATIONS.include?(identifier.to_sym)

  I18n.t("views.review.recommend_for_options.#{identifier}").titleize
rescue StandardError
  APMErrorHandler.report(
    "#{self.class} Error translating recommendation_title_for identifier '#{identifier}' for Review ID: #{id}",
  )
  ''
end

#refresh_relationsObject



260
261
262
263
264
265
266
267
268
# File 'app/models/review.rb', line 260

def refresh_relations
  TouchWorker.perform_async(User.name, user_id) if user_id.present?
  TouchWorker.perform_async(Reservation.name, reservation_id) if reservation_id.present?
  TouchWorker.perform_async(Restaurant.name, restaurant_id) if restaurant_id.present?
  TouchWorker.perform_async(Branch.name, branch_id) if branch_id.present?
  TouchWorker.perform_async(Blogger.name, blogger_id) if blogger_id.present?

  true
end


169
170
171
172
173
# File 'app/models/review.rb', line 169

def restaurant_link
  Rails.cache.fetch("model|review|#{id}|restaurant_link") do
    reservation.restaurant.friendly_id
  end
end

#restaurant_nameObject



184
185
186
# File 'app/models/review.rb', line 184

def restaurant_name
  reservation&.restaurant&.name || ''
end

#scoreObject



270
271
272
273
274
275
276
277
278
279
280
# File 'app/models/review.rb', line 270

def score
  if featured == 1
    100
  elsif review_photos_count.positive? && review.present?
    80 + rating.to_i + review_photos_count.to_i
  elsif review.present?
    60 + rating.to_i
  else
    40
  end
end

#to_paramObject



161
162
163
# File 'app/models/review.rb', line 161

def to_param
  id
end

#update_stat_before_destroy_reviewObject



282
283
284
285
286
287
288
# File 'app/models/review.rb', line 282

def update_stat_before_destroy_review
  changed_attr = transaction_changed_attributes
  Restaurants::ReviewStatGenerator.perform_async(id, changed_attr, 'destroy') if reservation&.restaurant_id&.present?
  if reservation&.restaurant_id&.present? && reservation&.restaurant&.branch.present?
    Restaurants::ReviewStatGenerator.perform_async(id, changed_attr, 'destroy', 'Branch')
  end
end

#user_nameObject



175
176
177
178
179
180
181
182
# File 'app/models/review.rb', line 175

def user_name
  name = reservation&.name || user&.name || ''
  return name if disclose_review?

  return I18n.t('hungryhub_diner') if name.blank?

  mask_name(name)
end