class Entry < ApplicationRecord belongs_to :created_by, class_name: "User", optional: true belongs_to :updated_by, class_name: "User", optional: true belongs_to :requested_by, class_name: "User", optional: true has_many :suggested_meanings, dependent: :destroy has_many :comments, as: :commentable, dependent: :destroy enum :category, %i[word phrase proper_name title reference other] enum :status, %i[requested approved active], default: :active validates :category, presence: true validate :at_least_one_translation scope :with_category, ->(cat) { cat.present? ? where(category: cat) : all } scope :requested, -> { where(status: :requested) } scope :approved, -> { where(status: :approved) } scope :active_entries, -> { where(status: :active) } def self.search(query, language_code: nil) return all if query.blank? terms = query.to_s.strip.split(/\s+/).map { |term| term.gsub('"', '""') }.reject(&:blank?) return all if terms.empty? prefix = valid_lang?(language_code) ? "#{language_code}:" : "" fts_query = terms.map { |term| "#{prefix}\"#{term}\"*" }.join(" ") joins("JOIN entries_fts ON entries_fts.rowid = entries.id") .where("entries_fts MATCH ?", fts_query) end def self.starts_with(prefix, language_code:) return none unless valid_lang?(language_code) return all if prefix.blank? where(arel_table[language_code].matches("#{sanitize_sql_like(prefix)}%")) end def self.alphabetical_for(language_code) return none unless valid_lang?(language_code) where.not(language_code => [ nil, "" ]) .order(arel_table[language_code].asc) end private def self.valid_lang?(code) SupportedLanguage.valid_codes.include?(code.to_s) end def at_least_one_translation if [ fi, en, sv, no, ru, de ].all?(&:blank?) errors.add(:base, "At least one language translation is required") end end end