# Upgrade to Rails 7. Javascript code refactoring

**URL:** <https://discuss.hotwired.dev/t/upgrade-to-rails-7-javascript-code-refactoring/5172>\
**Category:** General\
**Created:** [June 28, 2023, 8:45pm UTC](https://discuss.hotwired.dev/t/upgrade-to-rails-7-javascript-code-refactoring/5172 "2023-06-28T20:45:18Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![ably](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ably/32/3344_2.png) [@ably](https://discuss.hotwired.dev/u/ably)\
**Post date:** [June 28, 2023, 8:45pm UTC](https://discuss.hotwired.dev/t/upgrade-to-rails-7-javascript-code-refactoring/5172/1 "2023-06-28T20:45:18Z")

</div>

Hi! I’m working on upgrade my app from Rails 6 to Rails 7.  
Currently my app uses js in 3 different ways:

1. Small React App compiled by Webpack (`app/javascript/packs`)
2. JS in assets `app/assets/javascript`
3. Inline JS code in `.html.erb` files

**#1** React App was converted into a Stimulus controller. Webpack was replaced by importmaps. Easy, no issues here.  
**#2** Some of these js files could be moved to` /vendor/javascript`. Some of these could be converted into Stimulus Controllers.  
**#3** I have a lot of inline js code in `.html.erb` files. Code is usualy simple. It initializes something or calls some functions from #2.  
Here is an example:

```auto
  <script type='text/javascript'>
    $(function() {
      $("form select").select2({placeholder: "Select a product", width: '100%' });
    });
  </script>

```

I was thinking to create a Stimulus controller for select2, but some of the selects should have their own logic. Like:

- trigger some other js functions on change
- hide/show some elements on page
- fetch data from api

It seems that I will need to create too many stimulus controllers just for select2. And I will have dozen of Stimulus controllers.  
Maybe it is a good idea to leave inline code? But I don’t think that I could use it with importmaps.  
Is it still ok to have js in app/assets/javascript?  
What would you suggest?

---

<div class="post-metadata">

**Author:** ![moveson](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/moveson/32/2106_2.png) [@moveson](https://discuss.hotwired.dev/u/moveson)\
**Post date:** [July 4, 2023, 4:38pm UTC](https://discuss.hotwired.dev/t/upgrade-to-rails-7-javascript-code-refactoring/5172/2 "2023-07-04T16:38:37Z")

</div>

Congrats on modernizing your JS. Looks like you are on the right track.

I don’t see any issue with having a dozen or more Stimulus controllers, so long as they are reusable and easy to understand from reading the html.

Another thought would be to have one larger Stimulus controller that handles multiple input types. You can attach the controller to the select element and have conditional logic that executes depending on the attributes of that element.

Also, keep in mind that a lot of the work of replacing/hiding/showing elements on the page can be done via Turbo. For example, you can have a Stimulus controller action that fires off a GET turbo stream request, and then you can rely on Turbo to find the element it’s supposed to replace/hide/show.

---

<div class="post-metadata">

**Author:** ![sufyaniqbaldev](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/sufyaniqbaldev/32/2835_2.png) [@sufyaniqbaldev](https://discuss.hotwired.dev/u/sufyaniqbaldev)\
**Post date:** [July 6, 2023, 10:59am UTC](https://discuss.hotwired.dev/t/upgrade-to-rails-7-javascript-code-refactoring/5172/3 "2023-07-06T10:59:16Z")

</div>

Hi,  
You can Make a generic method for stimulus controller select2  
here is an example

```auto
window.select2drop = function (klass, model) {
  $(`#${klass}_${model}_id`).select2({
    ajax: {
      url: `/${model}s/`,
      dataType: 'json',
      data: function (params) {
        return {
          search: params.term,
          one_id: $(`#${klass}_one_id`).val(),
          two_id: $(`#${klass}_two_id`).val(),
          three_id: $(`#${klass}_three_id`).val(),
        };
      },
      processResults: function (data) {
        return { results: data };
      },
      cache: false,
    },
    allowClear: true,
    placeholder: `Select ${model}...`.replace(/_/g, ' '),
    templateResult: optionTemplate,
    templateSelection: selectionTemplate,
  });
};

```

```auto
and after that, you have to simply add in targetConnected call back method some code according to your page inputs
someTargetConnected(){
    select2drop('call', 'one');
    select2drop('call', 'two');
    select2drop('call', 'three');
}

```

it is an example you can modify according to your need
