title: Can JavaScript's Fetch be used to update param values in a Rails controller?
body: <p>Using JavaScript, Rails, as well as the DataTables API to set up a reporting interface for tracking task activity. Right now, I'm trying to figure out how to update the client-facing data table with new data by wiring up the interface's existing date selection buttons (e.g., Today, Last 7 Days, Last 30 Days, etc.) using JavaScript to switch between different <code>time_range</code> param values in the Rails controller.</p>
  <p>In the controller code, switching between these param values is meant to result in an update to a server-side query's <code>date_range</code> parameter. This parameter subsequently filters which data is returned by the server-side query by controlling what is specified in the db command's WHERE clause.</p>
  <p><strong><em>My problem</em></strong> is that the fetch request I've set up in my JavaScript is evidently failing to have any influence on switching which param values are being passed into the control flow at the top of the controller's <code>index</code> method.</p>
  <hr>
  <h3>Edit</h3>
  <p>Here's what the network pane in dev tools shows after making clicks on the &quot;Yesterday&quot; and &quot;Last 7 Days&quot; date selection buttons. These clicks appear to be running successful fetch requests:</p>
  <p><a href="https://i.stack.imgur.com/S48NU.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/S48NU.png" alt="Tracking Fetch requests in the Network activity tracker in DevTools" /></a></p>
  <p>One other thing I should point out here is that the data returned and viewable from the Network Tool's Preview is the <em>same</em> for my &quot;Yesterday&quot; fetch as it is for my &quot;Last 7 Days&quot; fetch. The whole point of making my fetch requests is that it retrieves a json data structure tailored to the date range selected in the interface via its interaction with the query written in the Rails controller.</p>
  <p>Over there, using <code>puts</code> to output the value of my <code>@date_range</code> variable after the control-flow block (delimited this debugging aspect with dash-blocks), Rails console is reporting the problem exactly - that my client-side code <em>is not</em> updating the value of <code>@date_range</code> as expected, however, it <em>does</em> show a <code>Parameters</code> hash at the top noting visibility of updates to the value passed to <code>time_range</code>:</p>
  <pre class="lang-none prettyprint-override"><code>Started GET &quot;/task_reporting?time_range=yesterday&quot; for ::1 at 2019-09-17 10:01:21 -0400
  Processing by TaskReportingController#index as JSON
    Parameters: {&quot;time_range&quot;=&gt;&quot;yesterday&quot;, &quot;task_reporting&quot;=&gt;{}}
    User Load (2.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
        ---------------------------------------------------------
        The value of @date_range is &gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
        ---------------------------------------------------------
     (13.1ms)          SELECT tasks.id, tasks.name, users.name, DATE_FORMAT(MAX(kits.updated_at), '%a. %b %d, %Y'),
          COUNT(DISTINCT(DATE(kits.updated_at))), COUNT(DISTINCT(kits.id))
          FROM kits
          JOIN tasks ON tasks.id = kits.task_id JOIN users ON users.id = kits.user_id JOIN annotations ON annotations.kit_id = kits.id
          WHERE kits.updated_at &gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
          GROUP BY tasks.id, users.name
  
  Completed 200 OK in 39ms (Views: 1.3ms | ActiveRecord: 15.7ms)
  
  
  Started GET &quot;/task_reporting?time_range=last_seven_days&quot; for ::1 at 2019-09-17 10:02:29 -0400
  Processing by TaskReportingController#index as JSON
    Parameters: {&quot;time_range&quot;=&gt;&quot;last_seven_days&quot;, &quot;task_reporting&quot;=&gt;{}}
    User Load (4.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
        ---------------------------------------------------------
        The value of @date_range is &gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
        ---------------------------------------------------------
     (1.7ms)          SELECT tasks.id, tasks.name, users.name, DATE_FORMAT(MAX(kits.updated_at), '%a. %b %d, %Y'),
          COUNT(DISTINCT(DATE(kits.updated_at))), COUNT(DISTINCT(kits.id))
          FROM kits
          JOIN tasks ON tasks.id = kits.task_id JOIN users ON users.id = kits.user_id JOIN annotations ON annotations.kit_id = kits.id
          WHERE kits.updated_at &gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
          GROUP BY tasks.id, users.name
  
  Completed 200 OK in 18ms (Views: 1.1ms | ActiveRecord: 6.0ms)
  </code></pre>
  <h3>End edit</h3>
  <hr>
  <p>More info described in code comments...</p>
  <p>My JavaScript (task_reporting.js.coffee) is called from the end of the view code for this tool:</p>
  <h3>Rails View (simplified)</h3>
  <p>index.html.haml:</p>
  <pre class="lang-rb prettyprint-override"><code>-content_for :action_specific_js do
    != &quot;task_reporting.init()&quot;
  </code></pre>
  <h3>JavaScript (jQuery + CoffeeScript)</h3>
  <pre class="lang-js prettyprint-override"><code>window.task_reporting = ( -&gt;
      // Important: initializes DataTable, loading default, thirty-day date-range data
      init: () -&gt;
            this.init_datepicker_button()
            this.init_daterange_buttons()
            $(&quot;#tasks_report&quot;).DataTable
                paging: false
                scrollY: &quot;400px&quot;
                scrollCollapse: true
                sAjaxSource: &quot;/task_reporting&quot;
                order: [[1, &quot;asc&quot;]]
      // Important: Believe the problem is here.
      // Method should send fetch request to server-side, altering query parameters in the controller
      render_table: (passed_time_range) -&gt;
            query_params = &quot;?time_range=#{passed_time_range}&quot;
            console.log(query_params)
  
            fetch(&quot;/task_reporting#{query_params}&quot;,
                method: 'GET'
                headers:
                    &quot;content-type&quot;: &quot;application/json&quot;
                    &quot;Accept&quot;: &quot;application/json&quot;
                credentials: &quot;same-origin&quot;
            )
            .then (response) -&gt; response.json()
            .then (data) -&gt;
              console.log(data)
              $(&quot;#tasks_report&quot;).DataTable().clear().rows.add(data).draw
            .catch((e) -&gt; console.error(&quot;Error:&quot;, e))
  
      // Not important: sets listener on date-range button (undeveloped)
      init_datepicker_button: -&gt;
            dateRangeButton = $(&quot;.datepickerContainer &gt; button#daterange&quot;)
            dateRangeButton.on &quot;click&quot;, this.init_dropdown
  
      // Sets listeners on individual date range buttons, calling pass_time_range to set param value in fetch
      init_daterange_buttons: -&gt;
            rangeItemButton = $(&quot;.range-item&quot;)
            rangeItemButton.on &quot;click&quot;, this.pass_time_range
  
      init_dropdown: -&gt;
            console.log &quot;dropdown here&quot;
  
      // Handles event on daterange buttons
      // Passes param value to render_table according to button's class name
      pass_time_range: (e) -&gt;
            e.preventDefault()
            // console.log e
            clickedTimeRange = e.target.className
            if clickedTimeRange.includes &quot;today&quot;
                task_reporting.render_table(&quot;today&quot;)
            else if clickedTimeRange.includes &quot;yesterday&quot;
                task_reporting.render_table(&quot;yesterday&quot;)
            else if clickedTimeRange.includes &quot;last_seven_days&quot;
                task_reporting.render_table(&quot;last_seven_days&quot;)
            else if clickedTimeRange.includes &quot;last_thirty_days&quot;
                task_reporting.render_table(&quot;last_thirty_days&quot;)
            else if clickedTimeRange.includes &quot;custom_range&quot;
                task_reporting.render_table(&quot;custom_range&quot;)
  )()
  </code></pre>
  <h3>Rails Controller</h3>
  <pre class="lang-rb prettyprint-override"><code>class TaskReportingController &lt; ApplicationController
    
    before_filter :authenticate
    
    def index
      
        # Checks param value and updates @date_range accordingly
        if params[:time_range] == &quot;range_today&quot;
          @date_range = '&gt;= CURDATE()'
        elsif params[:time_range] == &quot;range_yesterday&quot;
          @date_range = '&gt;= DATE_SUB(CURDATE(), INTERVAL 1 DAY)'
        elsif params[:time_range] == &quot;range_last_seven_days&quot;
          @date_range = '&gt;= DATE_SUB(CURDATE(), INTERVAL 7 DAY)'
        else params[:time_range] == &quot;range_last_thirty_days&quot;
          @date_range = '&gt;= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)'
        end
      
      # My fetch obviously fails to influence the :time_range param value
      # as the default thirty day range is always output here
      print &lt;&lt;-EOM
        ############
        The value of @date_range is #{@date_range}
        ############
      EOM
  
      # heredoc query
      query = &lt;&lt;-SQL
          SELECT tasks.name, users.name, DATE_FORMAT(MAX(kits.updated_at), '%a. %b %d, %Y'), 
          COUNT(DISTINCT(DATE(kits.updated_at))), COUNT(DISTINCT(kits.id)) 
          FROM kits
          JOIN tasks ON tasks.id = kits.task_id JOIN users ON users.id = kits.user_id JOIN annotations ON annotations.kit_id = kits.id
          WHERE kits.updated_at #{@date_range}
          GROUP BY tasks.id, users.name
        SQL
          
      query_result = Kit.connection.execute(query).to_a
  
      respond_to do |format|
        format.html
        format.json { render json: {&quot;aaData&quot;: query_result} }
      end
    end
  end
  </code></pre>
  <p>Looking for some direction in where I'm going wrong. Would welcome any advice on whether using fetch like this is the correct way to go about updating table data from the client-side using the DataTables API.</p>