Files
danbooru/app/models/application_record.rb
evazion b915f1c586 Revert "application model: move pagination extension to concern."
This reverts commit 7855e36d17.

Broke pagination due to incorrect memoization causing @paginator_count
to be shared between requests.
2020-02-25 01:07:09 -06:00

189 lines
5.4 KiB
Ruby

class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include Mentionable
extend HasBitFlags
extend Searchable
concerning :PaginationMethods do
class_methods do
def paginate(*args, **options)
extending(PaginationExtension).paginate(*args, **options)
end
def paginated_search(params, defaults: {}, count_pages: params[:search].present?)
search_params = params.fetch(:search, {}).permit!
search_params = defaults.merge(search_params).with_indifferent_access
search(search_params).paginate(params[:page], limit: params[:limit], search_count: count_pages)
end
end
end
concerning :PrivilegeMethods do
class_methods do
def visible(user)
all
end
end
end
concerning :ApiMethods do
class_methods do
def api_attributes(*attributes, including: [])
return @api_attributes if @api_attributes
if attributes.present?
@api_attributes = attributes
else
@api_attributes = attribute_types.reject { |name, attr| attr.type.in?([:inet, :tsvector]) }.keys.map(&:to_sym)
end
@api_attributes += including
@api_attributes
end
def available_includes
[]
end
def multiple_includes
reflections.reject { |k,v| v.macro != :has_many }.keys.map(&:to_sym)
end
def associated_models(name)
if reflections[name].options[:polymorphic]
associated_models = reflections[name].active_record.try(:model_types) || []
else
associated_models = [reflections[name].class_name]
end
end
end
def available_includes
self.class.available_includes
end
def api_attributes
self.class.api_attributes
end
def html_data_attributes
data_attributes = self.class.columns.select do |column|
column.type.in?([:integer, :boolean]) && !column.array?
end.map(&:name).map(&:to_sym)
api_attributes & data_attributes
end
def serializable_hash(options = {})
options ||= {}
if options[:only] && options[:only].is_a?(String)
options.delete(:methods)
options.delete(:include)
options.merge!(ParameterBuilder.serial_parameters(options[:only], self))
else
options[:methods] ||= []
attributes, methods = api_attributes.partition { |attr| has_attribute?(attr) }
methods += options[:methods]
options[:only] ||= attributes + methods
attributes &= options[:only]
methods &= options[:only]
options[:only] = attributes
options[:methods] = methods
options.delete(:methods) if options[:methods].empty?
end
hash = super(options)
hash.transform_keys { |key| key.delete("?") }
end
end
concerning :ActiveRecordExtensions do
class_methods do
def without_timeout
connection.execute("SET STATEMENT_TIMEOUT = 0") unless Rails.env == "test"
yield
ensure
connection.execute("SET STATEMENT_TIMEOUT = #{CurrentUser.user.try(:statement_timeout) || 3_000}") unless Rails.env == "test"
end
def with_timeout(n, default_value = nil, new_relic_params = {})
connection.execute("SET STATEMENT_TIMEOUT = #{n}") unless Rails.env == "test"
yield
rescue ::ActiveRecord::StatementInvalid => x
DanbooruLogger.log(x, expected: false, **new_relic_params)
return default_value
ensure
connection.execute("SET STATEMENT_TIMEOUT = #{CurrentUser.user.try(:statement_timeout) || 3_000}") unless Rails.env == "test"
end
end
end
concerning :PostgresExtensions do
class_methods do
def columns(*params)
super.reject {|x| x.sql_type == "tsvector"}
end
end
end
concerning :UserMethods do
class_methods do
def belongs_to_updater(**options)
class_eval do
belongs_to :updater, class_name: "User", **options
before_validation do |rec|
rec.updater_id = CurrentUser.id
rec.updater_ip_addr = CurrentUser.ip_addr if rec.respond_to?(:updater_ip_addr=)
end
end
end
end
end
concerning :DtextMethods do
def dtext_shortlink(**options)
"#{self.class.name.underscore.tr("_", " ")} ##{id}"
end
end
concerning :AttributeMethods do
class_methods do
# Defines `<attribute>_string`, `<attribute>_string=`, and `<attribute>=`
# methods for converting an array attribute to or from a string.
#
# The `<attribute>=` setter parses strings into an array using the
# `parse` regex. The resulting strings can be converted to another type
# with the `cast` option.
def array_attribute(name, parse: /[^[:space:]]+/, cast: :itself)
define_method "#{name}_string" do
send(name).join(" ")
end
define_method "#{name}_string=" do |value|
raise ArgumentError, "#{name} must be a String" unless value.respond_to?(:to_str)
send("#{name}=", value)
end
define_method "#{name}=" do |value|
if value.respond_to?(:to_str)
super value.to_str.scan(parse).map(&cast)
elsif value.respond_to?(:to_a)
super value.to_a
else
raise ArgumentError, "#{name} must be a String or an Array"
end
end
end
end
end
def warnings
@warnings ||= ActiveModel::Errors.new(self)
end
end