Skip to content

Commit

Permalink
Spike on attempting to serialize view components
Browse files Browse the repository at this point in the history
  • Loading branch information
rickychilcott committed Oct 10, 2020
1 parent e86e7d7 commit 87b4fd9
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ GEM
tzinfo (1.2.7)
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
view_component (2.19.1)
activesupport (>= 5.0.0, < 7.0)
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand All @@ -185,6 +187,7 @@ DEPENDENCIES
spy
sqlite3
standardrb
view_component

BUNDLED WITH
2.1.4
1 change: 1 addition & 0 deletions futurism.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "standardrb"
spec.add_development_dependency "sqlite3"
spec.add_development_dependency "spy"
spec.add_development_dependency "view_component"

spec.add_dependency "rack", "~> 2.0"
spec.add_dependency "rails", ">= 5.2"
Expand Down
1 change: 1 addition & 0 deletions lib/futurism.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "futurism/engine"
require "futurism/channel"
require "futurism/helpers"
require "futurism/shims/view_component_serializer"

module Futurism
extend ActiveSupport::Autoload
Expand Down
45 changes: 45 additions & 0 deletions lib/futurism/shims/view_component_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
return unless defined?(ViewComponent)

def serialize_value(value)
if value.is_a?(ActiveRecord::Base) && !value.new_record?
value.to_global_id.to_s
else
value
end
end

module ViewComponent
module FuturismSerializer
def to_futurism_serializable
transformed_raw_initialization_arguments.to_json
end

private

def transformed_raw_initialization_arguments
@raw_initialization_arguments.map do |value|
if value.is_a?(Hash)
require_relative "../shims/deep_transform_values" unless value.respond_to? :deep_transform_values
value.deep_transform_values { |val| serialize_value(val) }
else
serialize_value(value)
end
end
end
end

class Base
# Override base new method so that we can hack into the
# initialization process for each view component
# Ideally, a PR to the ViewComponent team would allow us to remove our implementation
# include FuturismSerializer

def self.new(*arguments, &block)
instance = allocate
instance.singleton_class.include(FuturismSerializer)
instance.instance_variable_set("@raw_initialization_arguments", arguments)
instance.send(:initialize, *arguments, &block)
instance
end
end
end
1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Configure Rails Environment
ENV["RAILS_ENV"] = "test"

require "view_component"
require_relative "../test/dummy/config/environment"
require "rails/test_help"
require "nokogiri"
Expand Down
76 changes: 76 additions & 0 deletions test/view_components/serializer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
require "test_helper"

class Futurism::Test < ActiveSupport::TestCase
test "component is a ViewComponent" do
assert_includes NoArgumentComponent.ancestors, ViewComponent::Base
assert_includes SimpleArgumentComponent.ancestors, ViewComponent::Base
assert_includes ComplexArgumentComponent.ancestors, ViewComponent::Base
end

test "component instance responds to #to_futurism_serializable" do
instance = NoArgumentComponent.new
assert_respond_to instance, :to_futurism_serializable
end

test "component instance saves no arguments" do
instance = NoArgumentComponent.new

assert_respond_to instance, :to_futurism_serializable
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), []
assert_equal instance.to_futurism_serializable, [].to_json
end

test "component instance saves simple arguments" do
instance = SimpleArgumentComponent.new(false, "/to/somewhere")

assert_respond_to instance, :to_futurism_serializable
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), [false, "/to/somewhere"]
assert_equal instance.to_futurism_serializable, [false, "/to/somewhere"].to_json
end

test "component instance saves complex arguments" do
post = Post.create title: "Lorem"
instance = ComplexArgumentComponent.new(false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post)

assert_respond_to instance, :to_futurism_serializable
assert_equal instance.instance_variable_get("@raw_initialization_arguments"), [false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post]
assert_equal instance.to_futurism_serializable, [false, "/to/somewhere", deactivate: "Deactivate!", active: "Activate!", ar_object: post.to_global_id.to_s].to_json
end
end

class NoArgumentComponent < ViewComponent::Base
def call
link_to active? ? "Deactivate" : "Activate", "/to/somewhere"
end

def active?
[true, false].sample
end
end

class SimpleArgumentComponent < ViewComponent::Base
def initialize(active, path)
@active, @path = active, path
end

def call
link_to active ? "Deactivate" : "Activate", path
end

attr_reader :active, :path
end

class ComplexArgumentComponent < ViewComponent::Base
def initialize(active, path, decativate: "Deactivate", activate: "Activate", **others)
@active, @path = active, path
@deactivate = decativate
@activate = activate
@others = others
end

def call
link_to active ? "Deactivate" : "Activate", path
end

attr_reader :active, :path, :deactivate, :activate, :others
end

0 comments on commit 87b4fd9

Please sign in to comment.