In Rails 7, Turbolinks is replaced by Hotwire / Turbo. This patches up web links so that they become AJAX-style requests just like Turbolinks did, but also patches up forms. On the whole, we found this broke swathes of our application.
Forms that already had some kind of JS behaviour attached conflicted.
Standard Rails error handling idioms - "set the flash and render :new/render :edit" - break, astonishingly; one must add status: :unprocessable_entity and cross fingers.
If the controller handling a form submission redirects to a URL that includes a patch anchor (...#foo), Turbo strips it.
In the end, there's only so much data: {turbo: false} it makes sense to scatter all over your code base. Worse, we're using SimpleForm, so this becomes the even-more-cumbersome html: {data: {turbo: false}}.
Is there a way to _globally disable Turbo just for forms (ideally all forms, whatever their origin - just leave the <form> tag and everything inside it completely alone please) but leave the rest of its behaviour unchanged?
I posted this Q&A on Stack Overflow as I couldn't find any other solutions out there. Clearly, there are numerous shortcomings and I would much prefer to see a simple configuration flag for Turbo that would make it ignore forms - this would be an overwhelmingly preferable approach.
I still don't have a full solution either way, because forms generated internally by Rails for e.g. a link_to(...method: delete) are still a problem, but I did work around some of it using some monkey patching.
On the one hand there are Rails forms:
Apparently, a data-turbo attribute's value apples to that node and all children so one can wrap e.g. a Rails-generated 'dynamic' form from e.g. a link_to(...method: delete) in a DIV with that attribute set and, at least, work around those problems on a case-by-case basis - though note, I'm having trouble making this work in some cases still.
If you have a lot of these, though, that's going to be intrusive and ugly, so it'd still be nice to have a way to have Turbo just ignore forms completely.
On the other hand there are SimpleForm forms:
SimpleForm provides no way to globally configure data attributes that will be added to form elements that it constructs. Previous requests for this in GitHub issues have so far been explicitly refused.
SimpleForm appears to provide no way to configure a wrapper that would go around the form as a whole, only custom wrappers for inputs within a form. So we can't easily just e.g. write a wrapper DIV as mentioned above.
I happened to be involved in a gem called Hoodoo that provides monkey patching facilities that lets you write patch modules which are more like subclasses - super is available to call up to the patched implementation - and, further, patches can be enabled or disabled dynamically and easily. Hoodoo is actually a Rack application service framework, so this is something of a sledgehammer - I always intended to one day extract this into its own gem, but at the time of writing, I have not got around to it (and several years have gone by) - but we can require just the part we need and ignore the rest.
Here, I patch SimpleForm's builder methods. These just call Rails' form helpers under the hood, so I might have a go at patching lower down in Rails instead, but anyway, the following worked.
In your Gemfile, declare the Hoodoo dependency but don't load all of its component parts as you won't want most of them.
# Hoodoo's monkey patch module is useful sometimes:
# https://rubygems.org/gems/hoodoo
#
# MUST use 'require: false' so that the Rack components of Hoodoo middleware
# do not get activated; this is a Rails app, not a Hoodoo service!
#
gem 'hoodoo', '~> 2.12', require: false
...then write something like config/initializers/simple_form_monkey_patch.rb which looks something like this:
require 'hoodoo/monkey'
module SimpleFormMonkey
module InstanceExtensions
def simple_form_for(record, options = {}, &block)
modified_options = {html: {data: {turbo: false}}}
modified_options.deep_merge!(options)
super(record, modified_options, &block)
end
end
end
Hoodoo::Monkey.register(
extension_module: SimpleFormMonkey,
target_unit: SimpleForm::ActionViewExtensions::FormHelper
)
Hoodoo::Monkey.enable(
extension_module: SimpleFormMonkey
)
...that'll do it. This has some risk as we're patching things which are - in terms of the module name & nesting - technically private to SimpleForm, but the method signature itself is at least public. You could patch ActionView::Helpers::FormHelper with an override for form_for instead, if you wanted to go lower level and patch an API that's been stable for a very long time. The code would be almost identical as the method signatures are the same.
I used Javascript to solve this problem:
document.querySelectorAll('form').forEach(function (el) {
el.dataset.turbo = false
})
No more flaky system tests due to randomly missing flash messages/alerts after form submissions and Devise also works perfectly again.
#kamilpogo your solution worked like a charm! ty!!! currently learning and following this GoRails tutorial before i ran into some turbo trouble trying to render "Thanks!" for anyone else out there.
basically, i added the javascript to in /layouts/application.html.erb like below:
<script>
document.querySelectorAll('form').forEach(function (el) {
el.dataset.turbo = false
})
</script>
<script src="js-bootstrap"></script>
</body>
</html>
UPDATE: comments in the videos have a different work around by setting turbo to 'false' and local to 'true' inside the form:
form_with model: #user, url: sign_up_path, local: true, data: { turbo:false } do |form|
I'm trying to update my DIV asynchronously. In Rails 2.3.8 I found out remote_form_tag where I could specify attribute :update => "DIV_TO_UPDATE". As I understood it was an easy way to do update html-element asynchronously, because developer didn't have to write JavaScript code!
But remote_form_tag was remoted in Rails 3 and methods form_for and form_tag don't contain attributes like :update. So I wonder if there is a way to do it in Rails 3.1?
PS I know how to do it with a little JavaScript (or CoffeeScript code) I'm looking for way without JS code at all.
I believe link_to_function is what you're after: http://apidock.com/rails/ActionView/Helpers/JavaScriptHelper/link_to_function
You can cheat by redirecting to the same url, if you'd like. It's an expensive operation. (You're just reloading the page, really.)
Horrible, I know. But it's what I did. I'm not very proud. :-(
Has anyone encountered an equivalent to HTMLPurifier for Rails apps? Essentially I need to clean up often terribly formed HTML generated by users before saving to the DB.
http://htmlpurifier.org/
You can use the sanitize method.
sanitize(html)
There is also a Sanitize gem.
Sanitize.clean(html)
I tend to prefer the Sanitize gem because it can be used as a before_save filter in your models instead of having to use the sanitize method in each of your views.
I'm working on upgrading an old Rails app (1.1.6) to Rails 3. Obviously, a lot has changed. One thing appears to be that Rails automatically escapes content dropped into the view. However, I have a situation where I have a helper generating IMG tags for me, and Rails is automatically escaping the resulting content.
<%= random_image('public/images/headers') %>
This results in escaped content, much like one would expect had I done this (in 1.1.6)
<%= h random_image('public/images/headers') %>
Is there a way to tell it to not escape?
<%= raw random_image('public/images/headers') %>
.html_safe
It may need to be inside the helper
There are there ways in which this can be achieved in rails 3 application
html_safe
raw
h
raw and h can only be used in controller and views these methods are defined in helpers.
html_safe can be used anywhere in a rails application i.e., can be used in models, helpers, controller etc.
For more information please read http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/
I want to create a Ruby on Rails layout and it should be in Liquid format.
Basically what I'm trying to do is to let the users to create their own layouts and save them in the database.
I tried to use
<%= Liquid::Template.parse(<code from database>).render %> in my layout.erb file but there I can't use the 'yield' command (since this is a layout I should have to have a way of rendering pages.)
But when I use 'layout.liquid' with {{ content_for_layout }} is will work find BUT, cannot load details from the database (I mean the HTML code..)
I hope I made myself clear :D )
Take a look at this Ruby on Rails plug-in:
http://github.com/akitaonrails/dynamic_liquid_templates
Next we have to find a way to intercept the default Ruby on Rails behaviour for your controller.
class MyAwesomeController
layout :get_my_db_layout
....
protected
def get_my_db_layout
'as_if_by_a_miracle.liquid' # add your db finder here
end
end
Then, overwrite LocalFileSystem#read_template_file with your own class / method, to get the template from the database. LocalFileSystem#read_template_file is a Liquid class.
I hope, that this idea is helpful.
please read Tobis article on
https://github.com/shopify/liquid/wiki/getting-liquid-to-work-in-rails
or look at this screencast
http://railscasts.com/episodes/118-liquid