ActiveModel not working with value to Object
dmlond opened this issue · comments
I am using stimulus-rails version 1.2.1
I have 2 Plain Objects that include ActiveModel::Serializers::JSON.
class Switcher
include ActiveModel::Serializers::JSON
attr_reader :object, :name, :labels, :host, :managed_deployments
def initialize(object)
@object = object
@name = object['metadata']['name']
@labels = object['metadata']['labels']
@host = object['spec']['host']
@managed_deployments = []
end
def manages?(deployment)
return false unless deployment.labels["oasis.duke.edu/#{@name}-managed"] == "true"
@managed_deployments << deployment
return true
end
def attributes
{'name' => nil, 'host' => nil, 'managed_deployments' => nil}
end
end
class Deployment
include ActiveModel::Serializers::JSON
attr_reader :object, :name, :labels
def initialize(object)
@object = object
@name = object['metadata']['name']
@labels = object['metadata']['labels']
end
def attributes
{'name' => nil}
end
end
I would like to pass an instance variable @Switchers that contains an Array of Switcher objects into a Stimulus Controller as a value of type Object.
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = {
switchers: Object
}
connect() {
console.log("Connected!");
console.log(this.switchersValue[0).name);
}
}
I have tried the following in my views
<div id="blockly_container"
data-controller="blockly"
data-blockly-switchers-value=<%= @switchers -%>
>
This ignores the ActiveModel::Serializers::JSON entirely and renders the entire object with its class name, which causes a JSON.parse error when the stimulus controller is loaded.
console output (truncated)
Connected! blockly_controller-7a40db76079b110b2667415e065bcec0d6ee8711eb74cd36f1c3854b0d506a2a.js:13:13
Error connecting controller
SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
...
the DOM looks like this
<div id="blockly_container" data-controller="blockly" data-blockly-switchers-value="[#<Oasis::Switcher:0x00007f80f9aa9930" @object="#<K8s::Resource" metadata="{:name=>"test-switcher-one"," :namespace=">"londo003"," :selflink=">"/apis/route.openshift.io/v1/namespaces/londo003/routes/test-switcher-one"," :uid=">"f785fca6-2c87-11ee-8fee-005056b47ad1"," :resourceversion=">"907690199"," :creationtimestamp=">"2023-07-27T14:14:58Z"," :labels=">{:"oasis.duke.edu/ingress-switcher"=>"true"," :"oasis.duke.edu="" ingress-switcher-name"=">"test-switcher-one"}," :annotations=">{:"openshift.io/host.generated"=>"true"}}," spec="{:host=>"test-switcher-one-londo003.ocp.dhe.duke.edu"," :to=">{:kind=>"Service"," :name=">"test-switcher-one"," :weight=">100}," :port=">{:targetPort=>"http"}," :tls=">{:termination=>"edge"," :insecureedgeterminationpolicy=">"Redirect"}," :wildcardpolicy=">"None"}," status="{:ingress=>[{:host=>"test-switcher-one-londo003.ocp.dhe.duke.edu"," :routername=">"router"," :conditions=">[{:type=>"Admitted"," :status=">"True"," :lasttransitiontime=">"2023-07-27T14:14:58Z"}]," apiversion=""route.openshift.io/v1"," kind=""Route">," @name=""test-switcher-one"," @labels="#<K8s::Resource" oasis.duke.edu="" ingress-switcher=""true"," ingress-switcher-name=""test-switcher-one">," @host=""test-switcher-one-londo003.ocp.dhe.duke.edu"," @managed_deployments="[#<Oasis::SwitchableDeployment:0x00007f80f9a8b390" :generation=">1," :environment=">"review-a"," ingress-switcher-managed"=">"true"," test-switcher-one-managed"=">"true"}," :selector=">{:matchLabels=>{:app=>"whoami"," :template=">{:metadata=>{:creationTimestamp=>nil," :spec=">{:containers=>[{:name=>"whoami"," :image=">"traefik/whoami"," :ports=">[{:containerPort=>8080," :protocol=">"TCP"}]," :env=">[{:name=>"WHOAMI_PORT_NUMBER"," :value=">"8080"}]," :resources=">{}," :terminationmessagepath=">"/dev/termination-log"," :terminationmessagepolicy=">"File"," :imagepullpolicy=">"Always"}]," :restartpolicy=">"Always"," :terminationgraceperiodseconds=">30," :dnspolicy=">"ClusterFirst"," :securitycontext=">{}," :schedulername=">"default-scheduler"}}," :strategy=">{:type=>"RollingUpdate"," :rollingupdate=">{:maxUnavailable=>"25%"," :maxsurge=">"25%"}}," :revisionhistorylimit=">10," :progressdeadlineseconds=">600}," :replicas=">1," :updatedreplicas=">1," :readyreplicas=">1," :availablereplicas=">1," :lastupdatetime=">"2023-07-27T14:15:31Z"," :reason=">"MinimumReplicasAvailable"," :message=">"Deployment" has="" minimum="" availability."},="" {:type=">"Progressing"," \"whoami-review-a-68848b457\"="" successfully="" progressed."}]},="" app=""whoami"," environment=""review-a"," ingress-switcher-managed=""true"," test-switcher-one-managed=""true">>]>," #<oasis::switcher:0x00007f80f9aa9430="">
...
</div>
I tried to use to_json
<div id="blockly_container"
data-controller="blockly"
data-blockly-switchers-value=<%= @switchers.to_json -%>
>
This results in the following error in the console
Connected! blockly_controller-7a40db76079b110b2667415e065bcec0d6ee8711eb74cd36f1c3854b0d506a2a.js:13:13
Error connecting controller
TypeError: expected value of type "object" but instead got value "[{"name":"test-switcher-one","host":"test-switcher-one-londo003.ocp.dhe.duke.edu","managed_deployments":[{"name":"whoami-review-a"}]},{"name":"test-switcher-two","host":"test-switcher-two-londo003.ocp.dhe.duke.edu","managed_deployments":[]}]" of type "array"
The rendered DOM element looks ok to me, except some html escapes that are sent in
<div id="blockly_container" data-controller="blockly" data-blockly-switchers-value="[{"name":"test-switcher-one","host":"test-switcher-one-londo003.ocp.dhe.duke.edu","managed_deployments":[{"name":"whoami-review-a"}]},{"name":"test-switcher-two","host":"test-switcher-two-londo003.ocp.dhe.duke.edu","managed_deployments":[]}]">
...
</div>
But if I change the value type to String, and use JSON.parse on the value, it gives me the expected object.
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = {
switchers: String
}
connect() {
console.log("Connected!");
console.log(JSON.parse(this.switchersValue)[0).name);
}
}
<div id="blockly_container"
data-controller="blockly"
data-blockly-switchers-value=<%= @switchers.to_json -%>
>
What is the expected behavior?
Believe you need to call to_json.html_safe
when setting the value. Either way, all of this is usage questions, not a bug. Please use the Hotwire forum or Discord for usage help.
it seems like a bug to me. The handbook states that the 'Object' type is decoded as JSON.parse(value). But the value I am passing into the value of type String can be turned into an object by passing it through JSON.parse(value), but the same value does not work with a value of type Object. This is true with or without html_safe.