diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..bfd9345 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 3fe9276..933fd31 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,6 @@ Extension of [ActiveResource](https://github.com/rails/activeresource) to allow integration with [ActiveAdmin](https://github.com/activeadmin/activeadmin). -## Disclaimer - -This gem is work in progress. There is only partial support of ActiveAdmin for now, and the are some specific limitation and requirements that need to be considered when using it. - -Pull Requests with improvements are welcomed :) - ## Installation Add this line to your Rails application's Gemfile: @@ -21,167 +15,28 @@ And then execute: $ bundle -## Usage - -This gem provides a base class that extends from ActiveResource and patches some missing functions in both ActiveAdmin and ActiveResource. The patches are executed when the gem is loaded. - -### ActiveAdminResource::Base - -This is the base class that you need to use to create ActiveAdmin enabled ActiveResource models. You need to extend your model with this base class, and define the minimum fields required by ActiveResource as in the following example: - -```ruby -class Market < ActiveAdminResource::Base - self.site = "http://localhost/api/" - - schema do - attribute 'id', :string - attribute 'name', :string - attribute 'base_currency', :string - attribute 'quote_currency', :string - end -end -``` - -This base class allows also to perform signed requests using the [Authograph gem](https://github.com/budacom/authograph/). To enable this, the class must implement the class method *self.secret* and return the private key in that method. Additionaly, an id of the requester can be provided by implementing the *self.agent_id* method as the following example shows: - -```ruby -class Account < ActiveAdminResource::Base - self.site = "http://localhost/signed_api/" - - def self.agent_id - #Return id - end - - def self.secret - #Return secret - end - - schema do - attribute 'id', :integer - attribute 'name', :string - end -end - -``` - -ActiveResource has partial support for relations between models. You can specify `has_one` and `has_many`relations just like its is done in ActiveRecord: - -```ruby -class Account < ActiveAdminResource::Base - self.site = "http://localhost/signed_api/" - - has_one :agent_data - has_many :withdrawals - - def self.agent_id - #Return id - end - - def self.secret - #Return secret - end - - schema do - attribute 'id', :integer - attribute 'name', :string - end -end - -``` - -The difference in how relations are handled is that for the subelement of a model (in this example `AgentData`) the url must include the parent -url with a symbol indicating the id of the parent record (in this example `:account_id`). - -```ruby -class AgentData < ActiveAdminResource::AgentDataBase - self.site = "http://localhost/signed_api/accounts/:account_id" - - def self.agent_id - #Return id - end - - def self.secret - #Return secret - end - - schema do - attribute 'a', :string - end -end -``` - -When accessing the subelement and trying to perform an action, this extra symbol must be included as a parameter to complete the url: - -```ruby -Account.find(4).agent_data.update_attributes(a: "asdf", account_id: 4) -``` - -### ActiveAdminResource::AgentDataBase +Since API quering changes from one ActiveResource integration to another, for this gem to work the proyect's base resource class must implement the following methods: -An additional base class called `AgentDataBase` is provided to model the special case of an `AgentData` object: +### `process_active_admin_collection_query(ransack:, reorder:, page:, per:)` -```ruby -class AgentData < ActiveAdminResource::AgentDataBase - self.site = "http://localhost/signed_api/" - - def self.agent_id - #Return id - end - - def self.secret - #Return secret - end - - schema do - attribute 'a', :string - end -end -``` - -When registering an ActiveAdminResource model with ActiveAdmin some additional considerations must be taken: - -* Batch actions are not supported, so they should be disabled. -* The *find_collection* method of *controller* must be overriden and return a paginated array as a result. -* Pagination is supported by providing pagination info in the server response. The currently supported pagination format expect a *meta* field in the response with a dictionary that has the following fields describing the pagination: *total_pages*, *total_count* and *current_page*. -When a response is requested, the pagination info is stored in *Model.format.pagination_info* and can be used to paginate the info accordingly. +This method will be called with the following arguments: +- `ransack`: ransack query activeadmin is trying to apply to collection +- `reorder`: ordering query activeadmin is trying to apply to collection +- `page`: page number +- `per`: results per page +The method must respond with an instance of `ActiveAdminResource::QueryResult`, that can be built using `ActiveAdminResource::QueryResult.new(collection, total_count, page)`, where: +- `collection`: an array of resource instances +- `total_count`: the total count of resources after applying filters (`nil` if not available) +- `page`: the current page (`nil` if not available) -The following example shows an ActiveAdminResource model being registered for ActiveAdmin and using the pagination schema explained before. - -```ruby - -ActiveAdmin.register Account do - config.batch_actions = false - - filter :names, as: :string, label: "Names" - filter :surnames, as: :string, label: "Surnames" - - controller do - def find_collection - default_per_page = 20 - per_page = params.fetch(:per_page, default_per_page) - query_params = params.fetch(:q, nil) - search_params = query_params.nil? ? {} : query_params.permit!.to_h - @search = OpenStruct.new(search_params.merge(conditions: [])) - result = Account.find(:all, params: { - order: params.fetch(:order, nil), - page: params.fetch(:page, 1), - per: per_page, - search: search_params - }) - pagination_info = Account.format.pagination_info - offset = (pagination_info["current_page"] - 1) * per_page - Kaminari.paginate_array(result, limit: result.count, offset: offset, total_count: pagination_info["total_count"]) - end - end -end - -``` +### `process_active_admin_resource_query(_id)` (optional) +If this method is defined, it will be called instead if `find` -### Limitations and Poorly tested cases +## Limitations -As explained before, there are several limitations and poorly tested cases in the current version: +**WARNING! There are several limitations and no tests, so use with caution** -* Batch actions are not supported -* POST, PUT and DELETE actions are not tested well and may have issues +* There is no way of telling activeadmin when to allow sorting or no +* There is no support for forms diff --git a/active_admin_resource.gemspec b/active_admin_resource.gemspec index fd81b25..0df50f9 100644 --- a/active_admin_resource.gemspec +++ b/active_admin_resource.gemspec @@ -19,5 +19,9 @@ Gem::Specification.new do |s| s.add_dependency 'money', '~> 6.6' s.add_dependency 'formtastic' s.add_development_dependency 'pry' + + s.add_development_dependency 'rails', '~> 6.1.7.4' + s.add_development_dependency 'rake' s.add_development_dependency 'rspec' + s.add_development_dependency 'rspec-rails' end diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000..da7cf89 Binary files /dev/null and b/lib/.DS_Store differ diff --git a/lib/active_admin_resource.rb b/lib/active_admin_resource.rb index d72070f..a2e4040 100644 --- a/lib/active_admin_resource.rb +++ b/lib/active_admin_resource.rb @@ -1,5 +1,7 @@ -require 'active_admin_resource/base' -require 'active_admin_resource/associations' -require 'active_admin_resource/gem_adaptors' -require 'active_admin_resource/agent_data_base' +require 'active_admin_resource/query_result' +require 'active_admin_resource/resource' +require 'active_admin_resource/resource_column' +require 'active_admin_resource/resource_class_adapter' +require 'active_admin_resource/resource_chain_helper' +require 'active_admin_resource/active_admin/namespace_patch' require 'active_admin_resource/railtie' diff --git a/lib/active_admin_resource/.DS_Store b/lib/active_admin_resource/.DS_Store new file mode 100644 index 0000000..aae1633 Binary files /dev/null and b/lib/active_admin_resource/.DS_Store differ diff --git a/lib/active_admin_resource/active_admin/namespace_patch.rb b/lib/active_admin_resource/active_admin/namespace_patch.rb new file mode 100644 index 0000000..1780a73 --- /dev/null +++ b/lib/active_admin_resource/active_admin/namespace_patch.rb @@ -0,0 +1,13 @@ +module ActiveAdminResource + module ActiveAdmin + module NamespacePatch + def find_or_build_resource(resource_class, options) + if resource_class < ActiveResource::Base + resources.add ActiveAdminResource::Resource.new(self, resource_class, options) + else + resources.add ::ActiveAdmin::Resource.new(self, resource_class, options) + end + end + end + end +end diff --git a/lib/active_admin_resource/agent_data_base.rb b/lib/active_admin_resource/agent_data_base.rb deleted file mode 100644 index 0f4d388..0000000 --- a/lib/active_admin_resource/agent_data_base.rb +++ /dev/null @@ -1,20 +0,0 @@ -module ActiveAdminResource - class AgentDataBase < Base - self.include_root_in_json = true - - def self.element_path(_id, prefix_options = {}, query_options = nil) - check_prefix_options(prefix_options) - - prefix_options, query_options = split_options(prefix_options) if query_options.nil? - "#{prefix(prefix_options)}#{collection_name}#{format_extension}#{query_string(query_options)}" - end - - def to_json(options = {}) - permitted_attributes = attributes.slice(*schema.keys) - rooted_attributes = {} - rooted_attributes[self.class.element_name] = permitted_attributes - encoded_attributes = include_root_in_json ? rooted_attributes : permitted_attributes - ActiveSupport::JSON.encode(encoded_attributes, options) - end - end -end diff --git a/lib/active_admin_resource/associations.rb b/lib/active_admin_resource/associations.rb deleted file mode 100644 index 13708a4..0000000 --- a/lib/active_admin_resource/associations.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'active_resource' - -module ActiveAdminResource - module Associations - def has_many(plural_model_name, options = {}) - klass = Object.const_get plural_model_name.to_s.singularize.classify - # Getter - define_method plural_model_name do - var = instance_variable_get("@#{plural_model_name}") - if !var.nil? - var - else - collection = if options[:as] # polymorphic - foreign_key = "#{options[:as]}_id" - foreign_type = "#{options[:as]}_type" - klass.where(foreign_type => model_name.name, foreign_key => id) - else - foreign_key = "#{model_name.name.downcase}_id" - klass.where(foreign_key => id) - end - instance_variable_set("@#{plural_model_name}", collection) - end - end - # Setter - define_method "#{plural_model_name}=" do |value| - instance_variable_set("@#{plural_model_name}", value) - end - end - - Enumerable.send(:define_method, 'and_preload') do |model_to_load| - model_to_load = model_to_load.to_s.singularize - klass_to_load = Object.const_get model_to_load.classify - foreign_ids = map { |collection_item| collection_item.send("#{model_to_load}_id") }.uniq - preloaded_items = if klass_to_load < ApplicationResource - # Class to load must support where(id: []) - klass_to_load.where(id: foreign_ids, per: foreign_ids.count) - elsif klass_to_load < ApplicationRecord - klass_to_load.where(id: foreign_ids) - else - raise "#{klass_to_load} is not from a supported preload type" - end - each do |collection_item| - corresponding_preloaded = preloaded_items.find do |pit| - pit.id == collection_item.send("#{model_to_load}_id") - end - collection_item.send("#{model_to_load}=", corresponding_preloaded) - end - self - end - end -end diff --git a/lib/active_admin_resource/base.rb b/lib/active_admin_resource/base.rb deleted file mode 100644 index ec4efab..0000000 --- a/lib/active_admin_resource/base.rb +++ /dev/null @@ -1,130 +0,0 @@ -require 'active_resource' -require 'active_admin_resource/associations' -require 'active_admin_resource/gem_adaptors' - -module ActiveAdminResource - class Base < ActiveResource::Base - extend ActiveAdminResource::Associations - extend Enumerize if defined? Enumerize - extend ActiveAdminResource::GemAdaptors::EnumerizeAdaptor - extend ActiveAdminResource::GemAdaptors::MoneyAdaptor - - class JsonFormatter - include ActiveResource::Formats::JsonFormat - - attr_reader :collection_name - attr_reader :pagination_info - - def initialize(collection_name) - @collection_name = collection_name.to_s - end - - def decode(json) - pre_process(ActiveSupport::JSON.decode(json)) - end - - private - - def pre_process(data) - @pagination_info = data['meta'] - data.delete('meta') - if data.is_a?(Hash) && data.keys.size == 1 && data.values.first.is_a?(Enumerable) - data.values.first - elsif data.is_a?(Array) && data.size == 1 - data.first - else - data - end - end - end - - self.format = JsonFormatter.new(collection_name) - - cattr_accessor :static_headers - self.static_headers = headers - - def self.inherited(model) - model.site = ENV['RESOURCES_API_URL'] if ENV.has_key?('RESOURCES_API_URL') - super - end - - def self.agent_id - ENV['RESOURCES_API_AGENT_ID'] - end - - def self.secret - ENV['RESOURCES_API_AGENT_SECRET'] - end - - def self.scope(name, body) - singleton_class.send(:define_method, name, &body) - # TODO: fix that a 2nd scope defined with same name in another model will override the 1st one, - # as all model's collections inherit from ActiveResource::Collection - ActiveResource::Collection.send(:define_method, name, &body) - end - - def self.human_attribute_name(attr, _options = {}) - I18n.t("activeresource.attributes.#{name.downcase}.#{attr}", - default: I18n.t("activerecord.attributes.#{name.downcase}.#{attr}", - default: attr.to_s.titleize)) - end - - def self.headers - new_headers = static_headers.clone - new_headers["Content-Type"] = "application/json" - new_headers["Accept"] = "application/json" - new_headers["X-Agent-Id"] = agent_id if !agent_id.nil? - new_headers - end - - def self.column_names - content_columns - end - - def self.content_columns - if @content_columns.nil? - @content_columns = Array.new - known_attributes.each do |name| - @content_columns << ResourceColumn.new(name) - end - end - @content_columns - end - - def self.columns - content_columns - end - - class ResourceColumn - attr_reader :name - - def initialize(name) - @name = name - end - - def type - :string - end - end - - def self.inheritance_column - '' - end - - def self.base_class - self - end - - def self.find_by(arg, *_args) - find(arg[primary_key]) - end - - class << self - def connection(refresh = false) - connection = super(refresh) - _connection.set_secret(secret) if !secret.nil? - connection - end - end - end -end diff --git a/lib/active_admin_resource/collection_patch.rb b/lib/active_admin_resource/collection_patch.rb deleted file mode 100644 index 4528153..0000000 --- a/lib/active_admin_resource/collection_patch.rb +++ /dev/null @@ -1,10 +0,0 @@ -module CollectionExtensions - def collection_size(c = collection) - if c.is_a? ActiveRecord::Relation - c = c.except :select, :order - c.group_values.present? ? c.count.count : c.count - else - c.respond_to?(:count) ? c.count : 0 - end - end -end diff --git a/lib/active_admin_resource/column_patch.rb b/lib/active_admin_resource/column_patch.rb deleted file mode 100644 index ee4305a..0000000 --- a/lib/active_admin_resource/column_patch.rb +++ /dev/null @@ -1,12 +0,0 @@ -module ColumnExtensions - def sortable? - if @options.has_key?(:sortable) - !!@options[:sortable] - elsif @resource_class - @resource_class.column_names.map { |c| c.is_a?(String) ? c : c.name } - .include?(sort_column_name) - else - @title.present? - end - end -end diff --git a/lib/active_admin_resource/connection_patch.rb b/lib/active_admin_resource/connection_patch.rb deleted file mode 100644 index 377e23d..0000000 --- a/lib/active_admin_resource/connection_patch.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'authograph' - -module ConnectionExtensions - def set_secret(secret) - @secret = secret - end - - def request(method, path, *arguments) - result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload| - payload[:method] = method - payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}" - Net::HTTP.start(site.host, site.port, use_ssl: defined? @ssl_options) do |http| - configure_http(http) - request = Net::HTTP::const_get(method.capitalize).new path - headers = arguments.last - headers.each do |key, value| - request[key] = value - end - request.body = arguments.first if arguments.length > 1 - Authograph.signer.sign(request, @secret) if !@secret.nil? - payload[:result] = http.request(request) - end - end - handle_response(result) - rescue Timeout::Error => e - raise TimeoutError.new(e.message) - rescue OpenSSL::SSL::SSLError => e - raise SSLError.new(e.message) - end -end diff --git a/lib/active_admin_resource/formtastic_addons_patch.rb b/lib/active_admin_resource/formtastic_addons_patch.rb deleted file mode 100644 index ab36e43..0000000 --- a/lib/active_admin_resource/formtastic_addons_patch.rb +++ /dev/null @@ -1,18 +0,0 @@ -module FormtasticAddonsExtensions - def seems_searchable? - false - end - - def klass - @object.try(:object).try(:klass) - end - - def ransacker? - klass.try(:_ransackers).try(:key?, method.to_s) - end - - def scope? - context = Ransack::Context.for klass rescue nil - context.respond_to?(:ransackable_scope?) && context.ransackable_scope?(method.to_s, klass) - end -end diff --git a/lib/active_admin_resource/gem_adaptors.rb b/lib/active_admin_resource/gem_adaptors.rb deleted file mode 100644 index 91b7595..0000000 --- a/lib/active_admin_resource/gem_adaptors.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'active_resource' -require 'formtastic' -require 'action_view' -require 'enumerize' - -module ActiveAdminResource - module GemAdaptors - module EnumerizeAdaptor - # Enumerize support - def enumerize(name, options = {}) - # Getter - define_method name do - enumerize_attr = self.class.send(name) - name ||= options[:default] - Enumerize::Value.new(enumerize_attr, attributes[name.to_sym]) - end - # Setter - define_method "#{name}=" do |value| - enumerize_attr = self.class.send(name) - unless value.to_s.in? enumerize_attr.values - raise ArgumentError.new "Invalid value '#{value}' for #{name} enumerized attribute" - end - attributes[name.to_sym] = value - end - super - end - end - - module MoneyAdaptor - def monetize(*fields) - options = fields.extract_options! - fields.each { |field| monetize_field(field, options) } - end - - def monetize_field(field, _options = {}) - # Getter - define_method field do - amount, currency = attributes[field.to_sym] - Money.from_amount(amount.to_f, currency) if amount - end - # Setter - define_method "#{field}=" do |new_amount| - field = field.to_sym - if new_amount.is_a?(Money) - amount = new_amount.amount - currency = new_amount.currency - elsif new_amount.is_a?(Numeric) - amount = new_amount - currency = attributes[field].try(:last) || MoneyRails.default_currency.try(:iso_code) || 'USD' - end - attributes[field] = [amount, currency].map(&:to_s) - end - end - end - end -end diff --git a/lib/active_admin_resource/query_result.rb b/lib/active_admin_resource/query_result.rb new file mode 100644 index 0000000..8b1dccb --- /dev/null +++ b/lib/active_admin_resource/query_result.rb @@ -0,0 +1,11 @@ +module ActiveAdminResource + class QueryResult + attr_reader :collection, :total_count, :page + + def initialize(_collection, _total_count, _page) + @collection = _collection + @total_count = _total_count + @page = _page + end + end +end diff --git a/lib/active_admin_resource/railtie.rb b/lib/active_admin_resource/railtie.rb index 9f465e1..f8bac74 100644 --- a/lib/active_admin_resource/railtie.rb +++ b/lib/active_admin_resource/railtie.rb @@ -1,15 +1,7 @@ -require 'active_admin_resource/formtastic_addons_patch' -require 'active_admin_resource/collection_patch' -require 'active_admin_resource/connection_patch' -require 'active_admin_resource/column_patch' - module ActiveAdminResource class Railtie < Rails::Railtie - initializer "railtie.configure_rails_initialization" do - ActiveResource::Connection.prepend(ConnectionExtensions) - ActiveAdmin::Helpers::Collection.prepend(CollectionExtensions) - ActiveAdmin::Filters::FormtasticAddons.prepend(FormtasticAddonsExtensions) - ActiveAdmin::Views::TableFor::Column.prepend(ColumnExtensions) + initializer "active_admin_resource.configure_admin_namespace" do + ::ActiveAdmin::Namespace.prepend(ActiveAdmin::NamespacePatch) end end end diff --git a/lib/active_admin_resource/railties/resource_api_mock/mock_store.rb b/lib/active_admin_resource/railties/resource_api_mock/mock_store.rb deleted file mode 100644 index dbfd99f..0000000 --- a/lib/active_admin_resource/railties/resource_api_mock/mock_store.rb +++ /dev/null @@ -1,56 +0,0 @@ -module ActiveAdminResource - class MockStore - @@store_hash = Hash.new([]) - - def self.select(model, query_params) - query_params.stringify_keys! - query_params.dup.each do |k, v| - if query_params["#{k}_id"].nil? && v.respond_to?(:id) - query_params["#{k}_id"] = v.id - query_params.delete(k) - end - end - store_for_model(model).select do |obj| - obj.attributes.slice(*query_params.keys) == query_params - end - end - - def self.insert(object) - model = object_to_model(object) - object.id ||= next_id(model) - @@store_hash[model] += [object] - end - - def self.update(object) - stored_object = store_for_object(object).find { |i| i.id == object.id } - raise "Object Not Found: #{object.class} ##{object.id}" unless stored_object - store_for_object(object).delete(stored_object) - insert(object) - end - - def self.delete(object) - store_for_object(object).delete(object) || - raise("Object Not Found: #{object.class} ##{object.id}") - end - - def self.drop - @@store_hash = Hash.new([]) - end - - def self.object_to_model(object) - object.class.name.downcase.to_sym - end - - def self.store_for_object(object) - store_for_model object_to_model(object) - end - - def self.store_for_model(model) - @@store_hash[model] - end - - def self.next_id(model) - (store_for_model(model).map(&:id).max || 0) + 1 - end - end -end diff --git a/lib/active_admin_resource/railties/resource_api_mock/resource_api_mock.rb b/lib/active_admin_resource/railties/resource_api_mock/resource_api_mock.rb deleted file mode 100644 index 5e918e8..0000000 --- a/lib/active_admin_resource/railties/resource_api_mock/resource_api_mock.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'active_resource' -require 'uri' - -module ActiveAdminResource - module ResourceApiMock - def self.included(klass) - klass.extend ClassMethods - klass.site = URI.parse('resource.api.mocked') - end - - def site - URI.parse('resource.api.mocked') - end - - def create - @persisted = true - MockStore.insert(self) - end - - def update - MockStore.update(self) - end - - def destroy - MockStore.delete(self) - end - - module ClassMethods - def find_every(options) - options = options[:params] if options.has_key? :params - model = model_name.singular.to_sym - MockStore.select(model, options) - end - - def find_single(id, options) - options = options[:params] if options.has_key? :params - model = model_name.singular.to_sym - MockStore.select(model, options.merge(id: id.to_i)).first - end - end - end -end diff --git a/lib/active_admin_resource/railties/rspec.rb b/lib/active_admin_resource/railties/rspec.rb deleted file mode 100644 index fe15121..0000000 --- a/lib/active_admin_resource/railties/rspec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'active_admin_resource/railties/resource_api_mock/resource_api_mock' -require 'active_admin_resource/railties/resource_api_mock/mock_store' -class ActiveAdminResource::Base - include ActiveAdminResource::ResourceApiMock -end - -RSpec.configure do |config| - config.before(:example) do |_example| - ActiveAdminResource::MockStore.drop - end -end diff --git a/lib/active_admin_resource/resource.rb b/lib/active_admin_resource/resource.rb new file mode 100644 index 0000000..7125233 --- /dev/null +++ b/lib/active_admin_resource/resource.rb @@ -0,0 +1,11 @@ +module ActiveAdminResource + class Resource < ActiveAdmin::Resource + def resource_class + @resource_class ||= ResourceClassAdapter.new(resource_class_name.constantize) + end + + def resource_quoted_column_name(_column) + _column + end + end +end diff --git a/lib/active_admin_resource/resource_chain_helper.rb b/lib/active_admin_resource/resource_chain_helper.rb new file mode 100644 index 0000000..4580c5e --- /dev/null +++ b/lib/active_admin_resource/resource_chain_helper.rb @@ -0,0 +1,73 @@ +module ActiveAdminResource + class ResourceChainHelper + def initialize(_resource_class_adapter) + @resource_class_adapter = _resource_class_adapter + @scope_args = [] # we need this variable, activeadmin accesses it directly :painharold: + end + + def object + @resource_class_adapter + end + + def reorder(_query) + @reorder = _query.split('.').last.parameterize(separator: '_') + self + end + + def page(_page) + @page = _page&.to_i + self + end + + def ransack(_ransack) + @ransack = _ransack + self + end + + def result + self + end + + def conditions + self + end + + def per(_limit_value) + actual_page = @page || 1 + + query_result = @resource_class_adapter.query_collection( + ransack: @ransack.try(:permit!)&.to_h, + reorder: @reorder, + page: actual_page, + per: _limit_value + ) + + actual_page = query_result.page if query_result.page.present? + + @ary = Kaminari.paginate_array( + query_result.collection, + limit: _limit_value, + offset: (actual_page - 1) * _limit_value, + total_count: query_result.total_count + ) + end + + def map(*_args) + @ary = @ary.map *_args + self + end + + def each(*_args) + @ary.each *_args + self + end + + def to_ary + @ary + end + + def method_missing(method_name, *args, &block) + @ransack[method_name] + end + end +end diff --git a/lib/active_admin_resource/resource_class_adapter.rb b/lib/active_admin_resource/resource_class_adapter.rb new file mode 100644 index 0000000..5b59736 --- /dev/null +++ b/lib/active_admin_resource/resource_class_adapter.rb @@ -0,0 +1,81 @@ +module ActiveAdminResource + class ResourceClassAdapter + extend Forwardable + + def_delegators :@resource_class, :name, :format, :primary_key + def_delegators :chain_helper, :reorder, :page, :ransack, :result, :per + + def initialize(_resource_class) + @resource_class = _resource_class + end + + def klass + self + end + + def inheritance_column + nil + end + + def _ransackers + {} + end + + def display_name + human_model = I18n.t("activerecord.models.#{model_name.i18n_key}.one", default: "") + return "#{human_model} ##{id}" if human_model.present? + + "#{model_name.name} ##{id}" + end + + def quoted_table_name + 'resource_not_table' + end + + def column_names + content_columns.map &:name + end + + def content_columns + @content_columns ||= @resource_class.known_attributes.map { |n| ResourceColumn.new(n) } + end + + def columns + content_columns + end + + def columns_hash + @columns_hash ||= begin + test = Hash.new { |h,k| puts "O!! #{k}"; nil } + content_columns.each { |c| test[c.name] = c } + test + end + end + + def find(_id) + if @resource_class.respond_to? :process_active_admin_resource_query + return @resource_class.process_active_admin_resource_query(_id) + end + + @resource_class.find(_id) + end + + def query_collection(*_params) + unless @resource_class.respond_to? :process_active_admin_collection_query + return ActiveAdminResource::QueryResult.new([], 0) + end + + @resource_class.process_active_admin_collection_query(*_params) + end + + def human_attribute_name(attr, _options = {}) + I18n.t("activerecord.attributes.#{name.downcase}.#{attr}", default: attr.to_s.titleize) + end + + private + + def chain_helper + @chain_helper ||= ResourceChainHelper.new(self) + end + end +end diff --git a/lib/active_admin_resource/resource_column.rb b/lib/active_admin_resource/resource_column.rb new file mode 100644 index 0000000..7174406 --- /dev/null +++ b/lib/active_admin_resource/resource_column.rb @@ -0,0 +1,13 @@ +module ActiveAdminResource + class ResourceColumn + attr_reader :name + + def initialize(name) + @name = name + end + + def type + :string + end + end +end