I have a simple form for creating a new model. The model has an attribute panel
that is set in the Controller. I think it should not matter, but panel
is an enum.
def new
@order = Order.new(panel: params[:panel])
end
In the view I create the following form (additional attributes omitted because not relevant for the problem)
<%= form_with model: @order do |f| %>
<%= f.hidden_field :panel %>
<% end %>
Problem
The problem is, that tis creates an input field for panel
with some hashed or encrypted value instead of the correct panel
value:
<input type="hidden" value="TfVtJbT4RBcPdCCqrkap+dA8uhJvotCH02+Isxx9ACmI2a9hcp4dOEszqztFy5A8pfIxqi35SW7BexQfYvq8BQ==" name="order[panel]" id="order_panel">
When trying to submit this form, I get an error that makes sense...
ArgumentError ('TfVtJbT4RBcPdCCqrkap+dA8uhJvotCH02+Isxx9ACmI2a9hcp4dOEszqztFy5A8pfIxqi35SW7BexQfYvq8BQ==' is not a valid panel)
Alternatives
I have tried to explicitly specify the value in the form, but this does not change the created HTML and thus still has the same problem.
<%= form_with model: @order do |f| %>
<%= f.hidden_field :panel, value: @order.panel %>
<% end %>
Workaround Solution
The only thing that works so far is to create a text_field
and set it to hidden
<%= form_with model: @order do |f| %>
<%= f.text_field :panel, value: @order.panel, hidden: true %>
<% end %>
This creates the correct value:
<input value="sport" type="text" name="order[panel]" id="order_panel" hidden="hidden">
Is this the correct way to do this? Why does hidden_field
not work as expected? What am I missing?
This is on the newest version of Ruby on Rails (Rails 6.0.2.1).
CSP
Upon further investigation, it seems this is somehow related to Content Security Policy and Turbolinks and/or UJS
This is my CSP:
Rails.application.config.content_security_policy do |policy|
policy.default_src :self, :https
policy.font_src :self, :https, :data
policy.img_src :self, :https, :data
policy.object_src :none
policy.script_src :self, :https
policy.style_src :self, :https, :unsafe_inline
policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
end
# If you are using UJS then enable automatic nonce generation
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Set the nonce only to specific directives
Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
# Rails.application.config.content_security_policy_report_only = true
I noticed that sometimes, when navigating around, the browser actually navigates to the link instead of Turbolinks doing their work (even though in these cases, no CSP Violation is logged), where in the same instance with NO CSP, Turbolinks are working as expected.
I have included my Javascript with nonce: content_security_policy_nonce
<%= javascript_pack_tag 'application', nonce: content_security_policy_nonce, 'data-turbolinks-track': 'reload' %>
If I remove nonce: content_security_policy_nonce
here, Turbolinks seem to work as expected again...