From 617bc9fbfc8699eafc0c5e454b73426e577f9ddc Mon Sep 17 00:00:00 2001 From: ihsan Date: Mon, 5 Sep 2022 12:51:41 +0700 Subject: [PATCH 01/10] updates, includes before query_scope callback is called --- Gemfile | 2 +- grape_api.gemspec | 2 +- lib/grape_api.rb | 3 +++ lib/grape_api/pagination.rb | 7 ++++--- lib/grape_api/resourceful/resource.rb | 28 +++++++++++++++++--------- lib/grape_api/resourceful/responder.rb | 4 ++-- lib/grape_api/version.rb | 2 +- 7 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Gemfile b/Gemfile index 5e1c662..303ee2b 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,6 @@ end # To use a debugger gem 'byebug', group: [:development, :test] -gem "grape", "~> 1.3" +gem "grape", "~> 1.6" gem "grape_on_rails_routes", "~> 0.3.2" gem "grape-entity", "~> 0.8.0" \ No newline at end of file diff --git a/grape_api.gemspec b/grape_api.gemspec index 1abeb2f..d50bfcd 100644 --- a/grape_api.gemspec +++ b/grape_api.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |spec| spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - spec.add_dependency "rails", "~> 6.1.3" + spec.add_dependency "rails", "~> 7.0.0" spec.add_dependency "grape" spec.add_dependency "grape_on_rails_routes", "~> 0.3.2" spec.add_dependency "grape-entity", "~> 0.8.0" diff --git a/lib/grape_api.rb b/lib/grape_api.rb index 185028e..7ce3570 100644 --- a/lib/grape_api.rb +++ b/lib/grape_api.rb @@ -15,6 +15,9 @@ module GrapeAPI mattr_accessor :base_api_class @@base_api_class = "API::Base" + mattr_accessor :api_namespace + @@api_namespace = "Api" + def self.config yield(self) end diff --git a/lib/grape_api/pagination.rb b/lib/grape_api/pagination.rb index 6890b34..7b6200e 100644 --- a/lib/grape_api/pagination.rb +++ b/lib/grape_api/pagination.rb @@ -98,10 +98,11 @@ def total_from(collection) private def paginate_with_pagy(collection, options) - if Pagy::VARS[:max_per_page] && options[:per_page] > Pagy::VARS[:max_per_page] - options[:per_page] = Pagy::VARS[:max_per_page] + default = Pagy::VERSION >= "4" ? Pagy::DEFAULT : Pagy::VARS + if default[:max_per_page] && options[:per_page] > default[:max_per_page] + options[:per_page] = default[:max_per_page] elsif options[:per_page] <= 0 - options[:per_page] = Pagy::VARS[:items] + options[:per_page] = default[:items] end pagy = pagy_from(collection, options) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index b6947e6..3b26aee 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -266,6 +266,10 @@ def posts @strong_parameter_object ||= ActionController::Parameters.new(params) end + def permitted_attributes + _resource_params + end + def _resource_params attributes = {} if(class_context) @@ -289,22 +293,28 @@ def _resource_params attributes end + def _apply_query_includes query + unless class_context.query_includes.blank? + includes = class_context.query_includes + if includes.is_a?(Array) + query = query.includes(*class_context.query_includes) + else + query = query.includes(class_context.query_includes) + end + end + query + end + def _query if(class_context) query = class_context.query_scope if query.respond_to?(:call) - query = instance_exec(model_class, &query) + model = _apply_query_includes(model_class) + query = instance_exec(model, &query) else + query = _apply_query_includes(query) query = query.where.not id: nil end - unless class_context.query_includes.blank? - includes = class_context.query_includes - if includes.is_a?(Array) - query = query.includes(*class_context.query_includes) - else - query = query.includes(class_context.query_includes) - end - end if(params[:order_by]) query = query.order params[:order_by] end diff --git a/lib/grape_api/resourceful/responder.rb b/lib/grape_api/resourceful/responder.rb index 7d4c044..564ed46 100644 --- a/lib/grape_api/resourceful/responder.rb +++ b/lib/grape_api/resourceful/responder.rb @@ -88,10 +88,10 @@ def presenter collection, options={} end ver = version.upcase begin - presenter_class = "::API::#{ver}::Presenters::#{presenter_name}".constantize + presenter_class = "::#{GrapeAPI.api_namespace}::#{ver}::Presenters::#{presenter_name}".constantize rescue NameError begin - presenter_class = "::API::#{ver}::Presenters::#{presenter_name.demodulize}".constantize + presenter_class = "::#{GrapeAPI.api_namespace}::#{ver}::Presenters::#{presenter_name.demodulize}".constantize rescue NameError presenter_class = presenter_name.constantize end diff --git a/lib/grape_api/version.rb b/lib/grape_api/version.rb index f74e800..f4dc86f 100644 --- a/lib/grape_api/version.rb +++ b/lib/grape_api/version.rb @@ -1,3 +1,3 @@ module GrapeAPI - VERSION = '1.0.0' + VERSION = '2.0.0' end From ec972f901f06ffe9092ce5ea160e8fe49f1f4230 Mon Sep 17 00:00:00 2001 From: ihsan Date: Tue, 6 Dec 2022 14:02:52 +0700 Subject: [PATCH 02/10] updates --- lib/grape_api/pagination.rb | 4 +++- lib/grape_api/resourceful/resource.rb | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/grape_api/pagination.rb b/lib/grape_api/pagination.rb index 7b6200e..7b5690b 100644 --- a/lib/grape_api/pagination.rb +++ b/lib/grape_api/pagination.rb @@ -121,7 +121,9 @@ def pagy_from(collection, options) else count = collection.is_a?(Array) ? collection.count : collection.count(:all) end - + if count.is_a?(Hash) + count = count.values.sum + end Pagy.new(count: count, items: options[:per_page], page: options[:page]) end diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index 3b26aee..7c17a4a 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -105,8 +105,10 @@ def model_klass_constant if class_exists?(model_klass) model_klass.constantize else - raise { ActiveRecord::RecordNotFound } + model_klass.constantize end + rescue + raise { ActiveRecord::RecordNotFound } end def attributes &block From 8e683266a9eaa07157ac6c2707d3b642960b56fa Mon Sep 17 00:00:00 2001 From: ihsan Date: Tue, 7 Feb 2023 16:28:54 +0700 Subject: [PATCH 03/10] updates --- lib/grape_api/pagination.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/grape_api/pagination.rb b/lib/grape_api/pagination.rb index 7b5690b..6b6876f 100644 --- a/lib/grape_api/pagination.rb +++ b/lib/grape_api/pagination.rb @@ -3,7 +3,7 @@ module Pagination def self.included(base) Grape::Endpoint.class_eval do def paginate(collection) - per_page = GrapeAPI.pagination.config.per_page_param(params) || route_setting(:per_page) + per_page = GrapeAPI.pagination.config.per_page_param(params) || route_setting(:per_page) || GrapeAPI.pagination.config.per_page_count options = { :page => GrapeAPI.pagination.config.page_param(params), @@ -24,7 +24,6 @@ def paginate(collection) per_page = GrapeAPI.pagination.config.per_page page = GrapeAPI.pagination.config.page include_total = GrapeAPI.pagination.config.include_total - header 'Link', links.join(', ') unless links.empty? header total, GrapeAPI::Pagination.total_from(pagy || collection).to_s if include_total header per_page, options[:per_page].to_s From 52024c82339152d0de7b53c638cece6d2a63e8e4 Mon Sep 17 00:00:00 2001 From: ihsan Date: Wed, 15 Feb 2023 15:30:23 +0700 Subject: [PATCH 04/10] add missing method build_recursive_params --- lib/grape_api/resourceful/resource.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index 7c17a4a..5a5f579 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -307,6 +307,21 @@ def _apply_query_includes query query end + def build_recursive_params(recursive_key:, parameters: posts, permitted_attributes:) + template = { recursive_key => permitted_attributes } + + nested_permit_list = template.deep_dup + current_node = nested_permit_list[recursive_key] + + nested_count = parameters.to_s.scan(/#{recursive_key}/).count + (1..nested_count).each do |i| + new_element = template.deep_dup + current_node << new_element + current_node = new_element[recursive_key] + end + nested_permit_list + end + def _query if(class_context) query = class_context.query_scope From f2e70f5aa333fab3a5591a7f53edb420328dce2d Mon Sep 17 00:00:00 2001 From: ihsan Date: Thu, 16 Feb 2023 14:48:17 +0700 Subject: [PATCH 05/10] fix strong param --- lib/grape_api/resourceful/resource.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index 5a5f579..7e78cbe 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -179,12 +179,16 @@ def resource_params_key(key = nil) key end - def resource_params_attributes(*attributes) + def resource_params_attributes(*attributes, &block) if attributes.empty? attributes = resourceful_params(:resource_params_attributes) end - unless attributes.empty? - set_resource_param(:resource_params_attributes, attributes) + if block_given? + set_resource_param(:resource_params_attributes, block) + else + if attributes.is_a?(Array) + set_resource_param(:resource_params_attributes, attributes) unless attributes.empty? + end end attributes end @@ -280,12 +284,12 @@ def _resource_params if attributes.empty? if posts.present? # attributes = params.require(class_context.resource_params_key) - if class_context.resource_params_attributes.empty? + if class_context.resource_params_attributes.blank? attributes = {} else _resource_params_attributes_ = class_context.resource_params_attributes - if _resource_params_attributes_[0].is_a?(Proc) - _resource_params_attributes_ = instance_exec(&_resource_params_attributes_[0]) + if _resource_params_attributes_.is_a?(Proc) + _resource_params_attributes_ = instance_exec(&_resource_params_attributes_) end attributes = posts.permit(_resource_params_attributes_) end From 4de3cb7075f693caccacc0e51f692a6e612e7d68 Mon Sep 17 00:00:00 2001 From: ihsan Date: Tue, 21 Feb 2023 01:14:46 +0700 Subject: [PATCH 06/10] update for ruby 3 --- lib/grape_api/resourceful/resource.rb | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index 7e78cbe..f3ae0a1 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -129,18 +129,22 @@ def query_includes(includes = nil) includes end - def query_scope(query = nil) + def query_scope(query = nil, &block) query = resourceful_params(:query_scope) if query.nil? + if block_given? + query = block + end query = model_klass_constant if query.nil? set_resource_param(:query_scope, query) #query.respond_to?(:call) ? query.call(model_klass_constant) : query query end - def resource_identifier(identifier = nil) + def resource_identifier(identifier = nil, &block) if identifier.nil? identifier = resourceful_params(:resource_identifier) - if(identifier.nil?) + identifier = block if block_given? + if identifier.nil? identifier = model_klass_constant.primary_key set_resource_param(:resource_identifier, identifier) end @@ -183,8 +187,9 @@ def resource_params_attributes(*attributes, &block) if attributes.empty? attributes = resourceful_params(:resource_params_attributes) end - if block_given? - set_resource_param(:resource_params_attributes, block) + attributes = block if block_given? + if attributes.is_a?(Proc) + set_resource_param(:resource_params_attributes, attributes) else if attributes.is_a?(Array) set_resource_param(:resource_params_attributes, attributes) unless attributes.empty? @@ -193,8 +198,9 @@ def resource_params_attributes(*attributes, &block) attributes end - def resource_friendly?(friendly = nil) + def resource_friendly?(friendly = nil, &block) friendly = resourceful_params[:resource_friendly] if friendly.nil? + friendly = block if block_given? if friendly.nil? set_resource_param(:resource_friendly, false) end @@ -202,7 +208,8 @@ def resource_friendly?(friendly = nil) friendly end - def got_resource_callback(proc = nil) + def got_resource_callback proc = nil &block + proc = block if block_given? proc = resourceful_params[:got_resource_callback] if proc.nil? unless proc.nil? set_resource_param(:got_resource_callback, proc) From 0df4cc36bf6d8d61c2ff21e336ba8e3c2eb99f7e Mon Sep 17 00:00:00 2001 From: ihsan Date: Tue, 21 Feb 2023 01:16:26 +0700 Subject: [PATCH 07/10] update for ruby 3 --- lib/grape_api/resourceful/resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index f3ae0a1..819d4f5 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -208,7 +208,7 @@ def resource_friendly?(friendly = nil, &block) friendly end - def got_resource_callback proc = nil &block + def got_resource_callback proc = nil, &block proc = block if block_given? proc = resourceful_params[:got_resource_callback] if proc.nil? unless proc.nil? From 7e1f5e38ed4250787f784194752f6618f1ec7ee4 Mon Sep 17 00:00:00 2001 From: ihsan Date: Tue, 21 Feb 2023 21:04:04 +0700 Subject: [PATCH 08/10] refactor resource module --- lib/grape_api/resourceful/resource.rb | 184 +++++++++++++++++--------- 1 file changed, 119 insertions(+), 65 deletions(-) diff --git a/lib/grape_api/resourceful/resource.rb b/lib/grape_api/resourceful/resource.rb index 819d4f5..405d0d5 100644 --- a/lib/grape_api/resourceful/resource.rb +++ b/lib/grape_api/resourceful/resource.rb @@ -2,12 +2,12 @@ module GrapeAPI module Resourceful module Resource - def self.included base - base.class_eval do + def self.included mod + mod.class_eval do class_attribute :resourceful_params_ self.resourceful_params_ = {} end - base.extend ClassMethods + mod.extend ClassMethods ::Grape::Endpoint.include HelperMethods if defined? ::Grape::Endpoint end @@ -16,6 +16,7 @@ module ClassMethods def resourceful_params key=nil if self.resourceful_params_[self.to_s].blank? self.resourceful_params_[self.to_s] = { + executed: [], model_klass: nil, resource_identifier: nil, resource_finder_key: nil, @@ -37,6 +38,10 @@ def resourceful_params key=nil end end + def is_executed? name + self.resourceful_params(:executed).include?(name) + end + def resourceful_params_merge! opts = {} current_opts = resourceful_params current_opts = current_opts.merge!(opts) @@ -48,13 +53,20 @@ def set_resource_param key, value end def fetch_resource_and_collection!(resourceful_params = {}, &block) - fetch_resource! resourceful_params, &block - fetch_collection! resourceful_params, &block + fetch_resource! resourceful_params + fetch_collection! resourceful_params + unless is_executed? :fetch_resource_and_collection! + yield if block_given? + set_resource_param :executed, resourceful_params(:executed).append(:fetch_resource_and_collection!).uniq + end end def fetch_resource!(resourceful_params = {}, &block) resourceful_params_merge!(resourceful_params) - yield if block_given? + unless is_executed? :fetch_resource! + yield if block_given? + set_resource_param :executed, resourceful_params(:executed).append(:fetch_resource!).uniq + end context = self after_validation do unless route.settings[:skip_resource] @@ -65,7 +77,10 @@ def fetch_resource!(resourceful_params = {}, &block) def fetch_collection!(resourceful_params = {}, &block) resourceful_params_merge!(resourceful_params) - yield if block_given? + unless is_executed? :fetch_collection! + yield if block_given? + set_resource_param :executed, resourceful_params(:executed).append(:fetch_collection!).uniq + end context = self after_validation do unless route.settings[:skip_collection] @@ -85,20 +100,25 @@ def actions(kind: :resource, only: [], except: [], also: []) end def resource_actions - resourceful_params[:resource_actions] + self.resourceful_params[:resource_actions] end def collection_actions - resourceful_params[:collection_actions] + self.resourceful_params[:collection_actions] end def model_klass(klass = nil) - klass = resourceful_params[:model_klass] if klass.nil? if klass.nil? - klass = self.to_s.demodulize.singularize.camelcase + klass = self.resourceful_params[:model_klass] + if klass.blank? + klass= self.to_s.demodulize.singularize.camelcase + set_resource_param :model_klass, klass + end + klass + else + set_resource_param :model_klass, klass + klass end - set_resource_param :model_klass, klass - klass end def model_klass_constant @@ -122,47 +142,62 @@ def class_exists?(klass) false end - def query_includes(includes = nil) - current_params = resourceful_params - includes = current_params[:query_includes] if includes.nil? - set_resource_param(:query_includes, includes) unless includes.nil? - includes + def query_includes(includes = nil, &block) + if includes.nil? && !block_given? + resourceful_params(:includes) + else + if block_given? + set_resource_param(:query_includes, block) + else + set_resource_param(:query_includes, includes) + end + end end def query_scope(query = nil, &block) - query = resourceful_params(:query_scope) if query.nil? - if block_given? - query = block + if query.blank? && !block_given? + resourceful_params(:query_scope) + else + if block_given? + set_resource_param :query_scope, block + else + set_resource_param :query_scope, query + end end - query = model_klass_constant if query.nil? - set_resource_param(:query_scope, query) - #query.respond_to?(:call) ? query.call(model_klass_constant) : query - query end def resource_identifier(identifier = nil, &block) - if identifier.nil? + if identifier.blank? && !block_given? identifier = resourceful_params(:resource_identifier) - identifier = block if block_given? - if identifier.nil? + if identifier.blank? identifier = model_klass_constant.primary_key - set_resource_param(:resource_identifier, identifier) + set_resource_param :resource_identifier, identifier end + identifier else - set_resource_param(:resource_identifier, identifier) + if block_given? + set_resource_param(:resource_identifier, block) + else + set_resource_param(:resource_identifier, identifier) + end end - identifier end - def resource_finder_key(key = nil) - key = resourceful_params(:resource_finder_key) if key.nil? - if key.nil? - key = model_klass_constant.primary_key - set_resource_param(:resource_finder_key, key) + def resource_finder_key(key = nil, &block) + if key.blank? && !block_given? + key = resourceful_params(:resource_finder_key) + if key.nil? + key = model_klass_constant.primary_key + set_resource_param :resource_finder_key, key + end + key else - set_resource_param(:resource_finder_key, key) + if block_given? + set_resource_param(:resource_finder_key, block) + else + set_resource_param(:resource_finder_key, identifier) + end end - key end def resource_identifier_and_finder_key identifier @@ -184,46 +219,61 @@ def resource_params_key(key = nil) end def resource_params_attributes(*attributes, &block) - if attributes.empty? - attributes = resourceful_params(:resource_params_attributes) - end - attributes = block if block_given? - if attributes.is_a?(Proc) - set_resource_param(:resource_params_attributes, attributes) + if attributes.blank? && !block_given? + resourceful_params(:resource_params_attributes) else - if attributes.is_a?(Array) - set_resource_param(:resource_params_attributes, attributes) unless attributes.empty? + if block_given? + set_resource_param(:resource_params_attributes, block) + else + set_resource_param(:resource_params_attributes, attributes) end end - attributes end def resource_friendly?(friendly = nil, &block) - friendly = resourceful_params[:resource_friendly] if friendly.nil? - friendly = block if block_given? - if friendly.nil? - set_resource_param(:resource_friendly, false) + if friendly.blank? && !block_given? + friendly = self.resourceful_params[:resource_friendly] + if friendly.blank? + friendly = false + set_resource_param :resource_friendly, friendly + end + friendly + else + if block_given? + set_resource_param :resource_friendly, block + else + set_resource_param :resource_friendly, friendly + end end - set_resource_param(:resource_friendly, friendly) - friendly end def got_resource_callback proc = nil, &block - proc = block if block_given? - proc = resourceful_params[:got_resource_callback] if proc.nil? - unless proc.nil? - set_resource_param(:got_resource_callback, proc) + if proc.blank? && !block_given? + self.resourceful_params[:got_resource_callback] + else + if block_given? + set_resource_param :got_resource_callback, block + else + set_resource_param :got_resource_callback, proc + end end - proc end - def should_paginate? pg = nil - pg = resourceful_params[:should_paginate] if pg.nil? - if pg.nil? - set_resource_param(:should_paginate, false) + def should_paginate? pg = nil, &block + if pg.blank? && !block_given? + pg = self.resourceful_params[:should_paginate] + if pg.blank? + pg = false + set_resource_param :should_paginate, pg + end + pg + else + if block_given? + set_resource_param :should_paginate, block + else + set_resource_param :should_paginate, pg + end end - set_resource_param(:should_paginate, pg) - pg end end @@ -403,7 +453,11 @@ def _set_collection(context) var_name = class_context do |context| context.model_klass.demodulize.underscore.downcase.pluralize end - @_resources = class_context.should_paginate?? paginate(_get_resources) : _get_resources + should_paginate = class_context.should_paginate? + if should_paginate.is_a?(Proc) + should_paginate = instance_exec(&should_paginate) + end + @_resources = should_paginate ? paginate(_get_resources) : _get_resources instance_variable_set("@#{var_name}", @_resources) end From cc63f6f2dc0ab787a8a4cadb683c464c54e29837 Mon Sep 17 00:00:00 2001 From: Vederis Leunardus Date: Fri, 18 Sep 2026 06:33:25 +0000 Subject: [PATCH 09/10] Upgrade to Rails 8 and Ruby 3.2; update dependencies and add smoke tests --- .devcontainer-lock.json | 24 ++ .devcontainer.json | 19 ++ .github/workflows/test.yml | 23 ++ Gemfile | 11 +- Gemfile.lock | 321 ++++++++++-------- bin/rails | 1 - grape_api.gemspec | 7 +- lib/grape_api/version.rb | 2 +- spec/dummy/config/application.rb | 1 - spec/dummy/config/environments/development.rb | 2 - spec/dummy/config/environments/production.rb | 2 - spec/dummy/config/initializers/assets.rb | 2 +- test/rails8_smoke_test.rb | 21 ++ test/test_helper.rb | 4 + 14 files changed, 291 insertions(+), 149 deletions(-) create mode 100644 .devcontainer-lock.json create mode 100644 .devcontainer.json create mode 100644 .github/workflows/test.yml create mode 100644 test/rails8_smoke_test.rb create mode 100644 test/test_helper.rb diff --git a/.devcontainer-lock.json b/.devcontainer-lock.json new file mode 100644 index 0000000..12ff591 --- /dev/null +++ b/.devcontainer-lock.json @@ -0,0 +1,24 @@ +{ + "features": { + "ghcr.io/devcontainers/features/copilot-cli:1": { + "version": "1.1.3", + "resolved": "ghcr.io/devcontainers/features/copilot-cli@sha256:e10d091ae7ef9b8d2ed5f601d75f5a090bc04acbac1a26d4cd3c0d5edde4ea10", + "integrity": "sha256:e10d091ae7ef9b8d2ed5f601d75f5a090bc04acbac1a26d4cd3c0d5edde4ea10" + }, + "ghcr.io/devcontainers/features/docker-in-docker:4.1.1": { + "version": "4.1.1", + "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:2b44bcb32e75d5a3c028479f7f957cf7d5e42d81761373025a8d501dd3748f88", + "integrity": "sha256:2b44bcb32e75d5a3c028479f7f957cf7d5e42d81761373025a8d501dd3748f88" + }, + "ghcr.io/devcontainers/features/node:2.1.0": { + "version": "2.1.0", + "resolved": "ghcr.io/devcontainers/features/node@sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857", + "integrity": "sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857" + }, + "ghcr.io/devcontainers/features/ruby:2": { + "version": "2.0.0", + "resolved": "ghcr.io/devcontainers/features/ruby@sha256:31b07475acf72a649c2f323d2ab5c15e1a0c286e7495be822b0850e240a9b5b7", + "integrity": "sha256:31b07475acf72a649c2f323d2ab5c15e1a0c286e7495be822b0850e240a9b5b7" + } + } +} diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 0000000..d1a61cf --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,19 @@ +{ + "image": "mcr.microsoft.com/devcontainers/ruby:trixie", + "features": { + "ghcr.io/devcontainers/features/ruby:2": { + "versionManager": "rbenv" // Options: "none", "rbenv", or "rvm" + }, + "ghcr.io/devcontainers/features/docker-in-docker:4.1.1": { + "version": "latest", + "moby": false + }, + "ghcr.io/devcontainers/features/node:2.1.0": { + "version": "24" + }, + "ghcr.io/devcontainers/features/copilot-cli:1": {} + }, + "mounts": [ + "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached" + ] +} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..0b00367 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Test + +on: + push: + pull_request: + +jobs: + test: + strategy: + fail-fast: false + matrix: + ruby: ["3.2"] + rails: ["~> 7.1.0", "~> 7.2.0", "~> 8.0.0", "~> 8.1.0"] + runs-on: ubuntu-latest + env: + RAILS_VERSION: ${{ matrix.rails }} + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - run: bundle exec ruby -Itest test/rails8_smoke_test.rb diff --git a/Gemfile b/Gemfile index 303ee2b..c44d667 100644 --- a/Gemfile +++ b/Gemfile @@ -4,12 +4,15 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in grape_api.gemspec. gemspec -group :development do - gem 'sqlite3' +rails_version = ENV.fetch("RAILS_VERSION", ">= 7.1") +gem "rails", rails_version + +group :development, :test do + gem 'sqlite3', '>= 2.1' end # To use a debugger gem 'byebug', group: [:development, :test] -gem "grape", "~> 1.6" +gem "grape", ">= 2.0", "< 3" gem "grape_on_rails_routes", "~> 0.3.2" -gem "grape-entity", "~> 0.8.0" \ No newline at end of file +gem "grape-entity", ">= 1.0", "< 2" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 90e0eb0..9bea279 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,81 +1,98 @@ PATH remote: . specs: - grape_api (0.1.0) - cancancan - grape - grape-cancan - grape-entity (~> 0.8.0) + grape_api (3.0.0) + grape (>= 2.0, < 3) + grape-entity (>= 1.0, < 2) grape_on_rails_routes (~> 0.3.2) - rails (~> 6.1.3) + rails (>= 7.1, < 9) GEM remote: https://rubygems.org/ specs: - actioncable (6.1.3) - actionpack (= 6.1.3) - activesupport (= 6.1.3) + action_text-trix (2.1.19) + railties + actioncable (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.3) - actionpack (= 6.1.3) - activejob (= 6.1.3) - activerecord (= 6.1.3) - activestorage (= 6.1.3) - activesupport (= 6.1.3) - mail (>= 2.7.1) - actionmailer (6.1.3) - actionpack (= 6.1.3) - actionview (= 6.1.3) - activejob (= 6.1.3) - activesupport (= 6.1.3) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (6.1.3) - actionview (= 6.1.3) - activesupport (= 6.1.3) - rack (~> 2.0, >= 2.0.9) + zeitwerk (~> 2.6) + actionmailbox (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) + mail (>= 2.8.0) + actionmailer (8.1.3.1) + actionpack (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activesupport (= 8.1.3.1) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.1.3.1) + actionview (= 8.1.3.1) + activesupport (= 8.1.3.1) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.3) - actionpack (= 6.1.3) - activerecord (= 6.1.3) - activestorage (= 6.1.3) - activesupport (= 6.1.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.1.3.1) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) + globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (6.1.3) - activesupport (= 6.1.3) + actionview (8.1.3.1) + activesupport (= 8.1.3.1) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.3) - activesupport (= 6.1.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.1.3.1) + activesupport (= 8.1.3.1) globalid (>= 0.3.6) - activemodel (6.1.3) - activesupport (= 6.1.3) - activerecord (6.1.3) - activemodel (= 6.1.3) - activesupport (= 6.1.3) - activestorage (6.1.3) - actionpack (= 6.1.3) - activejob (= 6.1.3) - activerecord (= 6.1.3) - activesupport (= 6.1.3) - marcel (~> 0.3.1) - mimemagic (~> 0.3.2) - activesupport (6.1.3) - concurrent-ruby (~> 1.0, >= 1.0.2) + activemodel (8.1.3.1) + activesupport (= 8.1.3.1) + activerecord (8.1.3.1) + activemodel (= 8.1.3.1) + activesupport (= 8.1.3.1) + timeout (>= 0.4.0) + activestorage (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activesupport (= 8.1.3.1) + marcel (~> 1.0) + activesupport (8.1.3.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + base64 (0.3.0) + bigdecimal (4.1.3) builder (3.2.4) byebug (11.1.3) - cancancan (3.2.1) - concurrent-ruby (1.1.8) + concurrent-ruby (1.3.8) + connection_pool (3.0.2) crass (1.0.6) + date (3.5.1) + drb (2.2.3) dry-configurable (0.12.1) concurrent-ruby (~> 1.0) dry-core (~> 0.5, >= 0.5.0) @@ -94,107 +111,143 @@ GEM dry-core (~> 0.5, >= 0.5) dry-inflector (~> 0.1, >= 0.1.2) dry-logic (~> 1.0, >= 1.0.2) - erubi (1.10.0) - globalid (0.4.2) - activesupport (>= 4.2.0) - grape (1.5.3) - activesupport - builder + erb (6.0.7) + erubi (1.13.1) + globalid (1.4.0) + activesupport (>= 6.1) + grape (2.4.0) + activesupport (>= 6.1) dry-types (>= 1.1) - mustermann-grape (~> 1.0.0) - rack (>= 1.3.0) - rack-accept - grape-cancan (0.0.3) - cancancan - grape (~> 1.2) - grape-entity (0.8.2) + mustermann-grape (~> 1.1.0) + rack (>= 2) + zeitwerk + grape-entity (1.1.0) activesupport (>= 3.0.0) - multi_json (>= 1.3.2) grape_on_rails_routes (0.3.2) rails (>= 3.1.1) i18n (1.8.9) concurrent-ruby (~> 1.0) - loofah (2.9.0) + io-console (0.9.4) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (3.0.2) + logger (1.7.0) + loofah (2.25.2) crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) + nokogiri (>= 1.12.0) + mail (2.9.1) + logger mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) - method_source (1.0.0) - mimemagic (0.3.9) - nokogiri (~> 1) - rake + net-imap + net-pop + net-smtp + marcel (1.2.1) mini_mime (1.0.3) - minitest (5.14.4) - multi_json (1.15.0) - mustermann (1.1.1) - ruby2_keywords (~> 0.0.1) - mustermann-grape (1.0.1) + minitest (6.0.6) + drb (~> 2.0) + prism (~> 1.5) + mustermann (4.0.0) + mustermann-grape (1.1.0) mustermann (>= 1.0.0) - nio4r (2.5.7) - nokogiri (1.11.2-x86_64-linux) + net-imap (0.6.7) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.4.0) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.5) + nokogiri (1.19.4-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-gnu) racc (~> 1.4) + pp (0.6.4) + prettyprint + prettyprint (0.2.0) + prism (1.9.0) racc (1.5.2) - rack (2.2.3) - rack-accept (0.4.5) - rack (>= 0.4) - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.1.3) - actioncable (= 6.1.3) - actionmailbox (= 6.1.3) - actionmailer (= 6.1.3) - actionpack (= 6.1.3) - actiontext (= 6.1.3) - actionview (= 6.1.3) - activejob (= 6.1.3) - activemodel (= 6.1.3) - activerecord (= 6.1.3) - activestorage (= 6.1.3) - activesupport (= 6.1.3) + rack (3.2.7) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.3.1) + rack (>= 3) + rails (8.1.3.1) + actioncable (= 8.1.3.1) + actionmailbox (= 8.1.3.1) + actionmailer (= 8.1.3.1) + actionpack (= 8.1.3.1) + actiontext (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activemodel (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) bundler (>= 1.15.0) - railties (= 6.1.3) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 8.1.3.1) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) - loofah (~> 2.3) - railties (6.1.3) - actionpack (= 6.1.3) - activesupport (= 6.1.3) - method_source - rake (>= 0.8.7) - thor (~> 1.0) + rails-html-sanitizer (1.7.1) + loofah (~> 2.25, >= 2.25.2) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rake (13.0.3) - ruby2_keywords (0.0.4) - sprockets (4.0.2) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.2) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - sqlite3 (1.4.2) - thor (1.1.0) - tzinfo (2.0.4) + rbs (4.2.0) + logger + prism (>= 1.6.0) + tsort + rdoc (8.0.0) + erb + prism (>= 1.6.0) + rbs (>= 4.0.0) + tsort + reline (0.7.0) + io-console (~> 0.5) + securerandom (0.4.1) + sqlite3 (2.9.6-aarch64-linux-gnu) + sqlite3 (2.9.6-x86_64-linux-gnu) + thor (1.5.0) + timeout (0.6.1) + tsort (0.2.0) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) + uri (1.1.1) + useragent (0.16.11) websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.4.2) + zeitwerk (2.8.3) PLATFORMS + aarch64-linux x86_64-linux DEPENDENCIES byebug - grape (~> 1.3) - grape-entity (~> 0.8.0) + grape (>= 2.0, < 3) + grape-entity (>= 1.0, < 2) grape_api! grape_on_rails_routes (~> 0.3.2) - sqlite3 + rails (>= 7.1) + sqlite3 (>= 2.1) BUNDLED WITH - 2.2.15 + 4.0.20 diff --git a/bin/rails b/bin/rails index 52cd21e..5f5acff 100755 --- a/bin/rails +++ b/bin/rails @@ -20,6 +20,5 @@ require "action_controller/railtie" require "action_mailer/railtie" require "action_view/railtie" require "action_cable/engine" -require "sprockets/railtie" # require "rails/test_unit/railtie" require "rails/engine/commands" diff --git a/grape_api.gemspec b/grape_api.gemspec index d50bfcd..f7efb77 100644 --- a/grape_api.gemspec +++ b/grape_api.gemspec @@ -21,9 +21,10 @@ Gem::Specification.new do |spec| spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - spec.add_dependency "rails", "~> 7.0.0" - spec.add_dependency "grape" + spec.required_ruby_version = ">= 3.2" + spec.add_dependency "rails", ">= 7.1", "< 9" + spec.add_dependency "grape", ">= 2.0", "< 3" spec.add_dependency "grape_on_rails_routes", "~> 0.3.2" - spec.add_dependency "grape-entity", "~> 0.8.0" + spec.add_dependency "grape-entity", ">= 1.0", "< 2" end diff --git a/lib/grape_api/version.rb b/lib/grape_api/version.rb index f4dc86f..845d3a3 100644 --- a/lib/grape_api/version.rb +++ b/lib/grape_api/version.rb @@ -1,3 +1,3 @@ module GrapeAPI - VERSION = '2.0.0' + VERSION = '3.0.0' end diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index b188f0f..e4ea4b8 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -12,7 +12,6 @@ require "action_text/engine" require "action_view/railtie" require "action_cable/engine" -require "sprockets/railtie" # require "rails/test_unit/railtie" # Require the gems listed in Gemfile, including any gems diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb index 438743c..c82ba91 100644 --- a/spec/dummy/config/environments/development.rb +++ b/spec/dummy/config/environments/development.rb @@ -56,10 +56,8 @@ # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. - config.assets.debug = true # Suppress logger output for asset requests. - config.assets.quiet = true # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb index abb1289..9e4c1e9 100644 --- a/spec/dummy/config/environments/production.rb +++ b/spec/dummy/config/environments/production.rb @@ -25,10 +25,8 @@ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress CSS using a preprocessor. - # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. - config.assets.compile = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = 'http://assets.example.com' diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb index fe48fc3..0f1b712 100644 --- a/spec/dummy/config/initializers/assets.rb +++ b/spec/dummy/config/initializers/assets.rb @@ -1,7 +1,7 @@ +# Asset pipeline is not required by the engine compatibility fixture. # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path diff --git a/test/rails8_smoke_test.rb b/test/rails8_smoke_test.rb new file mode 100644 index 0000000..c804cab --- /dev/null +++ b/test/rails8_smoke_test.rb @@ -0,0 +1,21 @@ +require_relative "test_helper" +require "rack/mock" + +class Rails8SmokeAPI < GrapeAPI::Endpoint::Base + get :ping do + { status: "ok" } + end +end + +class Rails8SmokeTest < Minitest::Test + def test_rails_and_gem_boot + assert_operator Gem::Version.new(Rails.version), :>=, Gem::Version.new("7.1") + assert_equal "3.0.0", GrapeAPI::VERSION + end + + def test_grape_endpoint_responds + response = Rack::MockRequest.new(Rails8SmokeAPI).get("/api/v1/ping") + assert_equal 200, response.status + assert_includes response.body, "ok" + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..d557cc5 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,4 @@ +ENV["RAILS_ENV"] ||= "test" +require "bundler/setup" +require "minitest/autorun" +require_relative "../spec/dummy/config/environment" From ebe32bd5a92bbe5801b71e59128adc22cadac53e Mon Sep 17 00:00:00 2001 From: Vederis Leunardus Date: Fri, 18 Sep 2026 06:37:32 +0000 Subject: [PATCH 10/10] Update dependencies in Gemfile.lock and adjust bundler cache setting in CI workflow --- .github/workflows/test.yml | 3 ++- Gemfile.lock | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b00367..4b3cf8d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,5 +19,6 @@ jobs: - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - bundler-cache: true + bundler-cache: false + - run: bundle install --jobs 4 --retry 3 - run: bundle exec ruby -Itest test/rails8_smoke_test.rb diff --git a/Gemfile.lock b/Gemfile.lock index 9bea279..c874d53 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -86,11 +86,11 @@ GEM uri (>= 0.13.1) base64 (0.3.0) bigdecimal (4.1.3) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) concurrent-ruby (1.3.8) connection_pool (3.0.2) - crass (1.0.6) + crass (1.0.7) date (3.5.1) drb (2.2.3) dry-configurable (0.12.1) @@ -125,7 +125,7 @@ GEM activesupport (>= 3.0.0) grape_on_rails_routes (0.3.2) rails (>= 3.1.1) - i18n (1.8.9) + i18n (1.15.2) concurrent-ruby (~> 1.0) io-console (0.9.4) irb (1.18.0) @@ -145,7 +145,7 @@ GEM net-pop net-smtp marcel (1.2.1) - mini_mime (1.0.3) + mini_mime (1.1.5) minitest (6.0.6) drb (~> 2.0) prism (~> 1.5) @@ -170,7 +170,7 @@ GEM prettyprint prettyprint (0.2.0) prism (1.9.0) - racc (1.5.2) + racc (1.8.1) rack (3.2.7) rack-session (2.1.2) base64 (>= 0.1.0) @@ -209,7 +209,7 @@ GEM thor (~> 1.0, >= 1.2.2) tsort (>= 0.2) zeitwerk (~> 2.6) - rake (13.0.3) + rake (13.4.2) rbs (4.2.0) logger prism (>= 1.6.0) @@ -231,7 +231,8 @@ GEM concurrent-ruby (~> 1.0) uri (1.1.1) useragent (0.16.11) - websocket-driver (0.7.3) + websocket-driver (0.8.2) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) zeitwerk (2.8.3)