-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #561 from senid231/529-improve-admin-ui-cdr-export…
…s-creation Improve CDR exports creation via Admin UI
- Loading branch information
Showing
12 changed files
with
326 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
class JsonAttributeModel | ||
# Base class for json attribute. | ||
# @see JsonAttributeType | ||
# @see WithJsonAttributes#json_attribute | ||
|
||
include ActiveModel::Model | ||
include ActiveModel::Attributes | ||
|
||
class << self | ||
def column_names | ||
attribute_types.keys.map(&:to_s) | ||
end | ||
end | ||
|
||
# serializes model as hash of it's attributes | ||
def as_json(options = {}) | ||
filled_attributes.with_indifferent_access.as_json(options) | ||
end | ||
|
||
# models are equal if classes and attributes values are the same | ||
def ==(other) | ||
return super unless other.is_a?(self.class) | ||
|
||
attributes.all? { |name, value| value == other.send(name) } | ||
end | ||
|
||
# Allows to call :presence validation on the json_attribute itself | ||
def blank? | ||
attributes.values.all?(&:blank?) | ||
end | ||
|
||
def [](attr_name) | ||
attribute(attr_name.to_sym) | ||
end | ||
|
||
def []=(attr_name, value) | ||
write_attribute(attr_name.to_sym, value) | ||
end | ||
|
||
def inspect | ||
attribute_string = filled_attributes.map { |name, value| "#{name}: #{value.inspect}" }.join(', ') | ||
"#<#{self.class.name} #{attribute_string}>" | ||
end | ||
|
||
private | ||
|
||
def filled_attributes | ||
attributes.reject { |_, value| value.nil? } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# frozen_string_literal: true | ||
|
||
module WithJsonAttributes | ||
# Wraps JSON column into a model. | ||
# @see JsonAttributeModel | ||
# @see JsonAttributeType | ||
# Usage: | ||
# | ||
# class JsonAttributeModel::UserConfig < JsonAttributeModel::Base | ||
# attribute :rate_limit, :integer | ||
# attribute :max_per_page, :integer | ||
# | ||
# validates :rate_limit, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than: 6_000 } | ||
# validates :max_per_page, numericality: { only_integer: true, greater_than_or_equal_to: 1 } | ||
# end | ||
# | ||
# class User < ApplicationRecord | ||
# include WithJsonAttributes | ||
# json_attribute :config, class_name: 'JsonAttributeModel::UserConfig' | ||
# end | ||
# | ||
# customer = customer.create(config: { rate_limit: 6_001, max_per_page: 10 }) | ||
# customer.persisted? # false | ||
# customer.errors.messages # { 'config.rate_limit': ['must be less than 6000'] } | ||
# customer.config.rate_limit = 600 | ||
# customer.save # true | ||
# customer.where(id: customer.id).pluck(:config).first # "{\"rate_limit\":600,\"max_per_page\":10}" | ||
|
||
extend ActiveSupport::Concern | ||
|
||
class_methods do | ||
# Defines json model attribute for provided column | ||
# @param name [Symbol] - name of json column (required) | ||
# @param class_name [String] - class name of corresponding model (required) | ||
def json_attribute(name, class_name:) | ||
attribute name, :json_object, class_name: class_name | ||
|
||
define_method("build_#{name}") do |attributes = {}| | ||
class_name.constantize.new(attributes) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'active_model_types/yeti_date_time_type' | ||
require 'active_model_types/json_attribute_type' | ||
|
||
ActiveModel::Type.register(:db_datetime, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# frozen_string_literal: true | ||
|
||
class JsonAttributeType < ActiveModel::Type::Value | ||
# Type for JSON model attribute. | ||
# @see JsonAttributeModel | ||
# @see WithJsonAttributes#json_attribute | ||
|
||
class CastError < StandardError | ||
end | ||
|
||
def initialize(class_name:) | ||
@model_class_name = class_name | ||
end | ||
|
||
def type | ||
:json | ||
end | ||
|
||
def cast_value(value) | ||
case value | ||
when String | ||
decoded = begin | ||
ActiveSupport::JSON.decode(value) | ||
rescue StandardError | ||
nil | ||
end | ||
model_class.new(decoded) unless decoded.nil? | ||
when Hash | ||
model_class.new(value) | ||
when ActionController::Parameters | ||
model_class.new(value.to_unsafe_h) | ||
when model_class | ||
value | ||
else | ||
raise CastError, "failed casting #{value.inspect}, only String, Hash or #{model_class} instances are allowed" | ||
end | ||
end | ||
|
||
def serialize(value) | ||
case value | ||
when Hash, model_class | ||
ActiveSupport::JSON.encode(value) | ||
else | ||
super | ||
end | ||
end | ||
|
||
def changed_in_place?(raw_old_value, new_value) | ||
cast_value(raw_old_value) != new_value | ||
end | ||
|
||
private | ||
|
||
def model_class | ||
@model_class ||= @model_class_name.constantize | ||
end | ||
end | ||
|
||
ActiveRecord::Type.register :json_object, JsonAttributeType |
Oops, something went wrong.