2014-06-06 16:34:07 +02:00
|
|
|
# Article category
|
2019-01-13 07:05:54 +01:00
|
|
|
class ArticleCategory < ApplicationRecord
|
2014-06-06 16:34:07 +02:00
|
|
|
# @!attribute name
|
|
|
|
# @return [String] Title of the category.
|
|
|
|
# @!attrubute description
|
|
|
|
# @return [String] Description (currently unused)
|
|
|
|
|
|
|
|
# @!attribute articles
|
|
|
|
# @return [Array<Article>] Articles with this category.
|
2011-05-07 21:55:24 +02:00
|
|
|
has_many :articles
|
2018-10-13 16:29:36 +02:00
|
|
|
# @!attribute order_articles
|
|
|
|
# @return [Array<OrderArticle>] Order articles with this category.
|
|
|
|
has_many :order_articles, through: :articles
|
|
|
|
# @!attribute orders
|
|
|
|
# @return [Array<Order>] Orders with articles in this category.
|
|
|
|
has_many :orders, through: :order_articles
|
2011-05-18 16:10:30 +02:00
|
|
|
|
2014-06-06 16:41:01 +02:00
|
|
|
normalize_attributes :name, :description
|
|
|
|
|
2023-05-12 13:01:12 +02:00
|
|
|
validates :name, presence: true, uniqueness: true, length: { minimum: 2 }
|
2011-05-07 21:55:24 +02:00
|
|
|
|
2012-12-11 10:53:01 +01:00
|
|
|
before_destroy :check_for_associated_articles
|
|
|
|
|
2023-05-12 13:01:12 +02:00
|
|
|
def self.ransackable_attributes(_auth_object = nil)
|
|
|
|
%w[id name]
|
2018-10-13 16:29:36 +02:00
|
|
|
end
|
|
|
|
|
2023-05-12 13:01:12 +02:00
|
|
|
def self.ransackable_associations(_auth_object = nil)
|
|
|
|
%w[articles order_articles orders]
|
2018-10-13 16:29:36 +02:00
|
|
|
end
|
|
|
|
|
2014-05-21 14:12:38 +02:00
|
|
|
# Find a category that matches a category name; may return nil.
|
|
|
|
# TODO more intelligence like remembering earlier associations (global and/or per-supplier)
|
|
|
|
def self.find_match(category)
|
2015-01-14 21:15:08 +01:00
|
|
|
return if category.blank? || category.length < 3
|
2021-03-01 15:27:26 +01:00
|
|
|
|
2014-05-21 14:12:38 +02:00
|
|
|
c = nil
|
|
|
|
## exact match - not needed, will be returned by next query as well
|
2021-03-01 15:27:26 +01:00
|
|
|
# c ||= ArticleCategory.where(name: category).first
|
2014-05-21 14:12:38 +02:00
|
|
|
# case-insensitive substring match (take the closest match = shortest)
|
2015-01-14 21:15:08 +01:00
|
|
|
c = ArticleCategory.where('name LIKE ?', "%#{category}%") unless c && c.any?
|
2014-05-21 14:12:38 +02:00
|
|
|
# case-insensitive phrase present in category description
|
2023-05-12 13:01:12 +02:00
|
|
|
unless c && c.any?
|
|
|
|
c = ArticleCategory.where('description LIKE ?', "%#{category}%").select do |s|
|
|
|
|
s.description.match(/(^|,)\s*#{category}\s*(,|$)/i)
|
|
|
|
end
|
|
|
|
end
|
2014-05-21 14:12:38 +02:00
|
|
|
# return closest match if there are multiple
|
2021-03-01 15:27:26 +01:00
|
|
|
c = c.sort_by { |s| s.name.length }.first if c.respond_to? :sort_by
|
2014-05-21 14:12:38 +02:00
|
|
|
c
|
|
|
|
end
|
|
|
|
|
2012-12-11 10:53:01 +01:00
|
|
|
protected
|
|
|
|
|
2014-06-06 16:34:07 +02:00
|
|
|
# Deny deleting the category when there are associated articles.
|
2012-12-11 10:53:01 +01:00
|
|
|
def check_for_associated_articles
|
2023-05-12 13:01:12 +02:00
|
|
|
return unless articles.undeleted.exists?
|
|
|
|
|
|
|
|
raise I18n.t('activerecord.errors.has_many_left',
|
|
|
|
collection: Article.model_name.human)
|
2012-12-11 10:53:01 +01:00
|
|
|
end
|
2011-05-07 21:55:24 +02:00
|
|
|
end
|