|
require "bundler/inline" |
|
|
|
gemfile(true) do |
|
source "https://rubygems.org" |
|
|
|
gem "activeresource", github: "rails/activeresource" |
|
gem "rails" |
|
gem "sqlite3" |
|
end |
|
|
|
require "active_record/railtie" |
|
require "minitest/autorun" |
|
|
|
# This connection will do for database-independent bug reports. |
|
ENV["DATABASE_URL"] = "sqlite3::memory:" |
|
|
|
class DemoApp < Rails::Application |
|
config.load_defaults Rails::VERSION::STRING.to_f |
|
config.eager_load = false |
|
config.logger = Logger.new($stdout) |
|
config.secret_key_base = "secret_key_base" |
|
|
|
config.active_record.encryption.primary_key = "primary_key" |
|
config.active_record.encryption.deterministic_key = "deterministic_key" |
|
config.active_record.encryption.key_derivation_salt = "key_derivation_salt" |
|
end |
|
Rails.application.initialize! |
|
|
|
ActiveRecord::Schema.define do |
|
create_table :posts, force: true do |t| |
|
t.json :cms_post, null: false |
|
t.virtual :cms_post_id, type: :string, stored: true, null: false, as: <<~SQL |
|
cms_post ->> 'id' |
|
SQL |
|
|
|
t.index :cms_post_id, unique: true |
|
end |
|
end |
|
|
|
module Cms |
|
class UrlEncodedFormat |
|
include ActiveResource::Formats::UrlEncodedFormat |
|
|
|
def initialize(&transform) |
|
@transform = transform |
|
end |
|
|
|
def encode(params, options = nil) |
|
params = params.deep_transform_keys(&@transform) |
|
|
|
super |
|
end |
|
end |
|
|
|
class ApplicationResource < ActiveResource::Base |
|
self.site = "https://cms.dev" |
|
self.query_format = UrlEncodedFormat.new { |key| key.to_s.camelcase(:lower) } |
|
end |
|
|
|
class Post < ApplicationResource |
|
schema do |
|
attribute :name, :string |
|
attribute :body, :string |
|
end |
|
end |
|
end |
|
|
|
class Post < ActiveRecord::Base |
|
serialize :cms_post, coder: ActiveResource::Coder.new(Cms::Post, :serializable_hash) |
|
|
|
delegate_missing_to :cms_post |
|
end |
|
|
|
require "rails/test_help" |
|
|
|
class PostTest < ActiveSupport::TestCase |
|
test "GET find interface" do |
|
ActiveResource::HttpMock.respond_to.get "/posts/abc123.json", {}, { |
|
id: "abc123", name: "Hello World", body: "From the API", created_on: "2025-11-14" |
|
}.to_json |
|
|
|
resource = Cms::Post.find("abc123") |
|
|
|
assert_kind_of Cms::Post, resource |
|
assert_equal "abc123", resource.id |
|
assert_equal "Hello World", resource.name |
|
assert_equal "From the API", resource.body |
|
assert_equal "2025-11-14", resource.created_on |
|
end |
|
|
|
test "GET query param interface" do |
|
ActiveResource::HttpMock.respond_to.get "/posts.json?sortBy=created_at", {}, [ |
|
{ id: "abc123", name: "Hello World", created_at: 10.minutes.ago }, |
|
{ id: "def456", name: "Hello Rails", created_at: 5.minutes.ago } |
|
].to_json |
|
|
|
resources = Cms::Post.where(sort_by: "created_at") |
|
|
|
assert_equal [ "Hello World", "Hello Rails" ], resources.map(&:name) |
|
end |
|
|
|
test "POST can map response with Errors to " do |
|
ActiveResource::HttpMock.respond_to.post "/posts.json" do |
|
response = { errors: [ "Name is taken" ] } |
|
ActiveResource::Response.new(response.to_json, 422) |
|
end |
|
|
|
resource = Cms::Post.new(name: "Let's Not") |
|
|
|
assert_raises ActiveResource::ResourceInvalid do |
|
resource.save! |
|
end |
|
assert_equal [ "is taken" ], resource.errors[:name] |
|
end |
|
|
|
test "stores Cms::Post instances as JSON" do |
|
cms_post = Cms::Post.new id: "abc123", name: "Hello", body: "World" |
|
Post.create!(cms_post:) |
|
|
|
# queries by synthesized column |
|
post = Post.find_by! cms_post_id: cms_post.id |
|
|
|
# uniqueness constraints enforced on synthesized column |
|
assert_raises(ActiveRecord::RecordNotUnique) { Post.create!(cms_post:) } |
|
|
|
# reads column to object instance |
|
assert_kind_of Cms::Post, post.cms_post |
|
assert_equal cms_post, post.cms_post |
|
|
|
# access through instance |
|
assert_equal cms_post.id, post.cms_post.id |
|
assert_equal cms_post.name, post.cms_post.name |
|
assert_equal cms_post.body, post.cms_post.body |
|
|
|
# access through delegation |
|
assert_equal cms_post.name, post.name |
|
assert_equal cms_post.body, post.body |
|
|
|
# virtual column access synthesized from JSON |
|
assert_equal cms_post.id, post.cms_post_id |
|
end |
|
|
|
test "Post can reload Cms::Post instance" do |
|
ActiveResource::HttpMock.respond_to.get "/posts/abc123.json", {}, { |
|
id: "abc123", name: "Goodbye" |
|
}.to_json |
|
cms_post = Cms::Post.new id: "abc123", name: "Hello" |
|
post = Post.create!(cms_post:) |
|
|
|
assert_changes -> { post.reload.name }, from: "Hello", to: "Goodbye" do |
|
post.cms_post.reload |
|
post.save! |
|
end |
|
end |
|
end |