Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ jobs:
- 7.2.2.1
- 8.0.4
- 8.1.2
- main
postgres-version:
- 15
exclude:
- ruby-version: 3.2
rails-version: main

steps:
- name: Install Postgresql
Expand All @@ -53,7 +57,11 @@ jobs:
- uses: actions/checkout@v4

- run: |
echo 'gem "rails", "${{ matrix.rails-version }}"' >> Gemfile
if [ "${{ matrix.rails-version }}" = "main" ]; then
echo 'gem "rails", github: "rails/rails", branch: "main"' >> Gemfile
else
echo 'gem "rails", "${{ matrix.rails-version }}"' >> Gemfile
fi
echo 'gem "wankel"' >> Gemfile

- uses: ruby/setup-ruby@v1
Expand Down
2 changes: 1 addition & 1 deletion lib/standard_api/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def self.included(klass)
klass.helper_method :includes, :orders, :model, :models, :resource_limit,
:default_limit
klass.before_action :set_standardapi_headers
klass.before_action :includes, except: [:destroy, :add_resource, :remove_resource, :json_schema]
klass.before_action :includes, only: [:create, :update, :create_resource]

klass.rescue_from StandardAPI::ParameterMissing, with: :bad_request
klass.rescue_from StandardAPI::UnpermittedParameters, with: :bad_request
Expand Down
24 changes: 22 additions & 2 deletions lib/standard_api/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ module Helpers
def serialize_attribute(json, record, name, type)
value = record.send(name)

json.set! name, type == :binary ? value&.unpack1('H*') : value
value = if type == :binary
value&.unpack1('H*')
elsif value.is_a?(BigDecimal)
value.to_s
else
value
end

json.set! name, value
end

def preloadables(record, includes)
Expand Down Expand Up @@ -76,7 +84,7 @@ def cache_key(record, includes)
record.cache_key(*timestamp_keys)
else
timestamp = timestamp_keys.map { |attr| record[attr]&.to_time }.compact.max
"#{record.model_name.cache_key}/#{record.id}-#{digest_hash(sort_hash(includes))}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
"#{record.model_name.cache_key}/#{record.id}-#{digest_hash(sort_hash(includes))}-#{timestamp.utc.to_fs(record.cache_timestamp_format)}"
end
end

Expand Down Expand Up @@ -154,6 +162,18 @@ def digest_hash(*hashes)
digest.hexdigest
end

def column_default_value(column, model)
return nil if column.default.nil?

default = if column.respond_to?(:fetch_cast_type)
column.fetch_cast_type(model.connection).deserialize(column.default)
else
column.cast_type.deserialize(column.default)
end

default.is_a?(BigDecimal) ? default.to_s : default
end

def json_column_type(sql_type)
case sql_type
when 'binary', 'bytea'
Expand Down
4 changes: 2 additions & 2 deletions lib/standard_api/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ class Railtie < ::Rails::Railtie
end

ActiveSupport.on_load(:before_configuration) do
::ActionDispatch::Routing::Mapper.send :include, StandardAPI::RouteHelpers
::ActionDispatch::Routing::Mapper.include StandardAPI::RouteHelpers
end

ActiveSupport.on_load(:action_view) do
::ActionView::Base.send :include, StandardAPI::Helpers
::ActionView::Base.include StandardAPI::Helpers
end
end

Expand Down
1 change: 1 addition & 0 deletions lib/standard_api/test_case.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require File.expand_path(File.join(__FILE__, '../test_case/update_tests'))

module StandardAPI::TestCase
include StandardAPI::Helpers

def assert_equal_or_nil(expected, *args)
if expected.nil?
Expand Down
2 changes: 1 addition & 1 deletion lib/standard_api/test_case/schema_tests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module IndexTests
assert_equal_or_nil column.comment, actual_column['comment']

if !column.default.nil?
default = column.fetch_cast_type(model.connection).deserialize(column.default)
default = column_default_value(column, model)
assert_equal default, actual_column['default']
else
assert_nil actual_column['default']
Expand Down
2 changes: 1 addition & 1 deletion lib/standard_api/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module StandardAPI
VERSION = '8.1.0'
VERSION = '8.2.0'
end
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ json.set! 'properties' do
column_schema[:readOnly] = true
end

if default = !column.default.nil? ? column.fetch_cast_type(model.connection).deserialize(column.default) : nil
if default = column_default_value(column, model)
column_schema[:default] = default
end

Expand Down
2 changes: 1 addition & 1 deletion lib/standard_api/views/application/_json_schema.streamer
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ json.object! do
column_schema[:readOnly] = true
end

if default = !column.default.nil? ? column.fetch_cast_type(model.connection).deserialize(column.default) : nil
if default = column_default_value(column, model)
column_schema[:default] = default
end

Expand Down
4 changes: 2 additions & 2 deletions lib/standard_api/views/application/_schema.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if model.nil? && controller_name == "application"
begin
controller_param = controller_name.underscore
const_name = "#{controller_param.camelize}Controller"
const = ActiveSupport::Dependencies.constantize(const_name)
const = const_name.constantize
if const.ancestors.include?(StandardAPI::Controller)
const
else
Expand Down Expand Up @@ -50,7 +50,7 @@ else

json.set! 'attributes' do
model.columns.each do |column|
default = !column.default.nil? ? column.fetch_cast_type(model.connection).deserialize(column.default) : nil
default = column_default_value(column, model)
type = case model.type_for_attribute(column.name)
when ::ActiveRecord::Enum::EnumType
default = model.defined_enums[column.name].key(default)
Expand Down
4 changes: 2 additions & 2 deletions lib/standard_api/views/application/_schema.streamer
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if model.nil? && controller_name == "application"
begin
controller_param = controller_name.underscore
const_name = "#{controller_param.camelize}Controller"
const = ActiveSupport::Dependencies.constantize(const_name)
const = const_name.constantize
if const.ancestors.include?(StandardAPI::Controller)
const
else
Expand Down Expand Up @@ -59,7 +59,7 @@ else
json.set! 'attributes' do
json.object! do
model.columns.each do |column|
default = !column.default.nil? ? column.fetch_cast_type(model.connection).deserialize(column.default) : nil
default = column_default_value(column, model)
type = case model.type_for_attribute(column.name)
when ::ActiveRecord::Enum::EnumType
default = model.defined_enums[column.name].key(default)
Expand Down
5 changes: 5 additions & 0 deletions test/standard_api/controller/include_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class ControllerIncludesTest < ActionDispatch::IntegrationTest
# end

# = Including an invalid include
#
# These tests verify that invalid includes are rejected *before* the action
# persists any data. The `before_action :includes` on create, update, and
# create_resource validates includes early so that a bad request is returned
# without side effects.

test "Controller#create with an invalid include" do
property = build(:property)
Expand Down
3 changes: 1 addition & 2 deletions test/standard_api/standard_api_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,8 @@ def normalizers

model.columns.each do |column|
assert_equal json_column_type(column.sql_type), schema.dig('models', model.name, 'attributes', column.name, 'type')
default = column.default
default = column_default_value(column, model)
if !default.nil?
default = column.fetch_cast_type(model.connection).deserialize(default)
assert_equal default, schema.dig('models', model.name, 'attributes', column.name, 'default')
else
assert_nil schema.dig('models', model.name, 'attributes', column.name, 'default')
Expand Down
2 changes: 1 addition & 1 deletion test/standard_api/test_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class TestApplication < Rails::Application
config.root = File.join(File.dirname(__FILE__), 'test_app')
config.secret_key_base = 'test key base'
config.eager_load = true
config.cache_classes = true
config.enable_reloading = false
config.action_controller.perform_caching = true
config.cache_store = :memory_store, { size: 8.megabytes }
config.action_dispatch.show_exceptions = :none
Expand Down
Loading