Skip to content

Instantly share code, notes, and snippets.

@salex
Last active March 7, 2020 16:52
Show Gist options
  • Save salex/a3898155c46871354f4f81e574547a55 to your computer and use it in GitHub Desktop.
Save salex/a3898155c46871354f4f81e574547a55 to your computer and use it in GitHub Desktop.
Rails Stimulus Rails.ujs approaches
.w3-row
p Test two, move element using Rails.ujs
/ This is a hidden form, payload may be usefull in other applications
= form_with( url:'/test/fire',method: :patch, html: {data: { type: "html", action: "ajax:success->testTwo#onPostSuccess",target:'testTwo.form' } },class:'w3-hide') do |form|
= form.text_area :payload, data: { target: "testTwo.payload" }
.w3-col.s6
p Left list (Cleared)
ul
- session[:test_list].each do |k,v|
- if v == 'c'
li[data-action="click->testTwo#unclear" data-id="#{k}"] = "#{k} item is #{v}"
.w3-col.s6
p Right list (Uncleared)
ul
- session[:test_list].each do |k,v|
- if v == 'n'
li[data-action="click->testTwo#clear" data-id="#{k}"] = "#{k} item is #{v}"
.w3-row
p Test one, move elements using “SJR” (Server-Generated Javascript).
.w3-col.s6
p Left list (Cleared)
ul
- session[:test_list].each do |k,v|
- if v == 'c'
li[data-action="click->testOne#unclear" data-id="#{k}"] = "#{k} item is #{v}"
.w3-col.s6
p Right list (Uncleared)
ul
- session[:test_list].each do |k,v|
- if v == 'n'
li[data-action="click->testOne#clear" data-id="#{k}"] = "#{k} item is #{v}"
document.getElementById('testone').innerHTML=('<%= escape_javascript(render partial: "test/sjr") %>');
// also the same for unclear.js.erb
.w3-container.w3-white.min-height
h1 This is a test and only a test
p This page simulates balancing checking transactions with a bank. The left list contains transactions cleared with bank, The right list are transaction that have not cleared the bank. Clicking on an item in either list moves it from one state to the other. This could olso be a ToDo list, moving task from unDone to Done, etc, etc
.w3-row-padding
.w3-col.s6
#testone[data-controller="testOne"]
= render partial:'test/sjr'
.w3-col.s6
div[data-controller="testTwo" data-target="testTwo.refresh"]
= render partial:'test/fire'
.w3-row
.w3-col.s6
#testthree[data-controller="testThree" data-target="testThree.refresh" data-action="ajax:success->testThree#onSuccess"]
= render partial:'test/link'
.w3-col.s6
p Test 4?
class TestController < ApplicationController
def test
session[:test_list] = {"1"=>'c',"2"=>'c',"3"=>'c',"4"=>'c',"5"=>'c',"6"=>'n',"7"=>'n',"8"=>'n',"9"=>'n',"10"=>'n'}
end
def clear
id = params[:id]
session[:test_list][id] = 'c'
end
def unclear
id = params[:id]
session[:test_list][id] = 'n'
end
def fire
dir,id = params[:payload].split('|')
session[:test_list][id] = dir
render partial:'test/fire'
end
def link
dir,id = params[:payload].split('|')
session[:test_list][id] = dir
render partial:'test/link'
end
end
import { Controller } from "stimulus"
import Rails from '@rails/ujs';
export default class extends Controller {
static targets = []
connect() {
console.log("opened test one")
}
unclear(){
const item = event.target
const id = item.dataset.id
Rails.ajax({
url: "/test/unclear.js",
type: "patch",
data: "id="+id,
})
}
clear(){
const item = event.target
const id = item.dataset.id
Rails.ajax({
url: "/test/clear.js",
type: "patch",
data: "id="+id,
})
}
}
import { Controller } from "stimulus"
import Rails from '@rails/ujs';
export default class extends Controller {
static targets = [ 'refresh']
connect() {
console.log("opened test thtee")
}
onSuccess(event) {
console.log("twas called")
let [data, status, xhr] = event.detail;
this.refreshTarget.innerHTML = xhr.response;
}
}
import { Controller } from "stimulus"
import Rails from '@rails/ujs';
export default class extends Controller {
static targets = ["payload",'form', 'refresh']
connect() {
console.log("opened test two")
}
unclear(){
const item = event.target
const form = this.formTarget
const payload = this.payloadTarget
payload.value = 'n|' + item.dataset.id
Rails.fire(form,'submit')
}
clear(){
const item = event.target
const form = this.formTarget
const payload = this.payloadTarget
payload.value = 'c|' + item.dataset.id
Rails.fire(form,'submit')
}
onPostSuccess(event) {
let [data, status, xhr] = event.detail;
this.refreshTarget.innerHTML = xhr.response;
this.payloadTarget.value = "";
}
}
@salex
Copy link
Author

salex commented Mar 7, 2020

I've spent the last several months trying to upgrade some existing apps to Rails 6. I've been down many tangents and have learned a lot, but it should not have taken that long. Here are some of the obstacles I ran into.

  • The Rails 5 app used jQuery and Zurb Foundation. Didn't realize that webpacker was going to make that combination unworkable - at least in the number of weeks I spend trying to make them work. * Got foundation working 99%, but some things (think sticky menu) would break with turbo links.
  • Gave up on foundation and adopted w3.css, it really has about all I needed and no javascript dependency. I then ran into problems with jQuery. Gave up on jQuery. I then just decided to recreate the application by starting from scratch and creating a new rails 6 application.
  • I then started to juggle moveing a few more applications to the new approach.

Now I've never been a fan of javascript. When coffee script came out, I did start adding some sprinkles to my code, which soon turned into a mess. Almost all were jQuery, most were simple stuff, toggling stuff, a few ajax calls and a few more complex things that I'm not sure how I got them to work!

I started to attack the jQuery/coffeescript jungle using Stimulus.js. Did a few simple things then did my most complex tasks, an accounting double entry ledger. Things had to balance and if they didn't, you needed to stuff the unbalance somewhere until the entire form had all required elements and balanced. I felt proud and started of on a few other tasks. basically some $.ajax stuff.

With no jQuery I had to dig into Rails.ujs. I must have 300 links in my browser history looking for answers on how to move from jQuery to stimulus and rails.ujs. I'd get one thing working and then would run into something a little different and it would not work. This was mainly me in that I really don't understand half of this javascript stuff. I also realize, that even though I've been playing with Rails since 0.9, I don't know all I should know.

Like where in the hell to you find out about the html object in a form_with helper! Its a one liner that says you can put stuff in it!

I finally found a page that described how to submit a form that updated the DOM without a js.erb file. Stimulus & Rails Remote Forms that gave a fairly good explanation, so I copied and pasted and got it to work - but I didn't really understand it.

When I tried the approach on another task, it didn't work! It was not a direct copy and paste, but just using the same approach. In the post he explained:

Fortunately, leveraging rails-ujs together with Stimulus is actually fairly straightforward! The two keys to it are (i) we need to specify the remote form to have html datatype, and (ii) specify a Stimulus action for the ajax:success event.

There was that html datatype thingie.

I decided to just write a little test page and controllers to try to understand what I didn't understand. That's what this gist is about.

This is just a controller that displays three approaches to doing the same thing. The same thing simulates moving a state in a checking balance form from uncleared to cleared or uncleared too cleared. Or it's like moving a todo task from incomplete to complete.

I just use a object in the session that represents a model ID and a State (think `Split.where(…)..pluck(:id,:reconcile)

The first approach uses the Rail.ajax approach with a x.js.erb file

The second approach uses the Form and Rails.fire approach.

The third approach is what I found after reading the Rails Guide (outdated) for the umpty umpt time and found out the answer was there, just not well explained.

I now know a little bit more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment