3

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...

MeXx
  • 3,357
  • 24
  • 39
  • I can't reproduce this error on my sandbox rails project `6.0.1`. It works as it supposed – Roman Alekseiev Jan 23 '20 at 15:20
  • Thanks, I did not think to test it with a blank project. I've updated that project to Rails 6 just recently. After your comment I looked around and found that the issue seems to come from a CSP configuration: `Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }`. Without this, however, UJS is being blocked... – MeXx Jan 23 '20 at 15:31
  • Anyway, on a clean project it seems to work correctly with my current CSP, even with the nonce enabled as well... – MeXx Jan 23 '20 at 15:54
  • Maybe it is a good idea to open issue on github, if you made update to rails 6 properly. Good luck, though – Roman Alekseiev Jan 23 '20 at 19:15
  • 1
    @MeXx I am facing this issue now, the only config I have is `config.action_view.embed_authenticity_token_in_remote_forms = true`. It seems to me that that config is adding a authenticity token via hidden input, but also screwing up the next hidden input. I have added a fake `<%= hidden_field_tag :skip, "bam" %>`, so the action_view doesn't screw the one I want... – Orgmir May 21 '20 at 12:32
  • Are you using Firefox for your tests? – ErvalhouS Sep 08 '20 at 12:32
  • Yes I was using Firefox. Right now, I can not remember anymore if I have tested this in other browsers as well – MeXx Sep 10 '20 at 12:19

1 Answers1

4

You haven't specified the browser in your question, but there is an issue with Firefox autocomplete being too aggressive and overriding hidden field values. The issue is closed but there are people complaining about it using version 75 in may.

Try disabling autocomplete for the given field like so:

<%= f.hidden_field :panel, autocomplete: 'off' %>
ErvalhouS
  • 4,178
  • 1
  • 22
  • 38