This time, I will implement a simple chart function in Ruby on Rails using ajax and chat.js. As an example, let's draw the growth record of the person selected from the pull-down menu. (Horizontal axis: recording date, vertical axis: height) The Rails version is 6.0.3.3.
Column name fi | Column description | Data type |
---|---|---|
id | ID | integer |
name | name | string |
height | height | float |
rec_date | Height record date | date |
created_at | Registration date | datetime |
updated_at | Update date | datetime |
This time, the height record data for two people is registered in seeds.rb
.
Gemfile
gem 'chart-js-rails', '~> 0.1.4'
command
yarn add jquery chart.js
config/webpack/environment.js
const { environment } = require('@rails/webpacker')
//Make jquery available
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
app/javascript/packs/application.js
// chart.Added for js use
require("chart.js")
command
rails generate model Height name:string height:float rec_date:date
rails db:migrate
seeds.rb
Height.create!(
[
{
name: 'Takashi',
height: 150.3,
rec_date: "1990-01-03",
},
{
name: 'Takashi',
height: 168.3,
rec_date: "1996-03-03",
},
{
name: 'Takashi',
height: 178.4,
rec_date: "2003-04-03",
},
{
name: 'snow',
height: 130.3,
rec_date: "1987-05-07",
},
{
name: 'snow',
height: 144.1,
rec_date: "1995-04-23",
},
{
name: 'snow',
height: 153.6,
rec_date: "2000-05-13",
},
]
)
command
rails db:seed
Prepare an index action and a search action in chart_sample_controller.rb
. The search action is an action to receive a request transmission using $ .ajax ()
and return the height data corresponding to the name in json format by in-model search.
command
rails generate controller ChartSample index search
That's it for creating the packages, gems, models, and controllers you need. Next, prepare the route settings and views.
config/routes.rb
Rails.application.routes.draw do
get 'chart_sample/index'
get '/chart_sample/search', to: 'chart_sample#search'
end
Views
The js file is read by javascript_pack_tag
, but here the script that draws the graph using Ajax + chart.js is written in jQuery. The js file is described in ʻapp / javascript / packs / chart_sample / chart_user_height.js`.
html:app/view/chart_sample/index.html.erb
<h1>Growth record</h1>
<div class="contents">
<select id="area">
<option value="0">Please select</option>
<option value="1">Takashi</option>
<option value="2">snow</option>
</select>
</div>
<div class="canvas">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
<%= javascript_pack_tag 'chart_sample/chart_user_height' %>
The view screen looks like this: When it's done, select the name from the pull-down menu → the graph of the growth record is displayed below.
Ajax+chart.js The code here is long, so I will explain it step by step and paste the source code together at the end.
app/javascript/packs/chart_sample/chart_user_height.js (1)
$(document).on('turbolinks:load', function () {
$(function () {
//Load your own function for chart display
var chart_func = require("../origin_func.js")
$('#area').change(function() {
var selected_name = $('option:selected').text();
var selected_index = $('option:selected').val();
Here, in order to prevent the phenomenon that jQuery does not work properly due to page transition due to the influence of Ajax etc., turbolinks: load
is set to fire both when loading for the first time and reloading. ʻOrigin_func.jsis loading a function of the chart drawing function by chart.js. This will be explained later. The index of the select box of the previous view is defined as
selected_index and the name is defined as
selected_name`.
app/javascript/packs/chart_sample/chart_user_height.js (2)
if (selected_index > 0) {
//Request the value of SelectBox in json format using ajax
// messages/The index action of the searches controller receives
$.ajax({
type: 'GET', //Request type
url: '/chart_sample/search', //URL to send the request
data: { name: selected_name }, //Data to send to the server
dataType: 'json' //Type returned from the server
})
Here, selected_index> 0
, that is, what is processed when the name (this time" Takashi "or" Yuki ") is selected. Send the name obtained using $ .ajax ()
to the controller. As per the route setting above, it will be sent to the search action of chart_sample_controller.rb
.
This section describes the contents of the search
action of the controller that received the request before the continuation of chart_user_height.js
.
app/controllers/chart_sample_controller.rb
class ChartSampleController < ApplicationController
def index
end
def search
#↓ Search processing code(A list of search results is entered)
@height = Height.where('name = (?)', "#{params[:name]}").order(rec_date: "ASC")
respond_to do |format|
#If the requested format is HTML
format.html { redirect_to :root }
#If the requested format is JSON format
format.json { render json: @height }
end
end
end
In the search
action, the request (person's name) sent by Ajax earlier is stored in params [: name], so a match search is performed in the Height
model, and the rec_date
of the contents returned from the model is searched. Sorted in chronological order. This is because the horizontal axis will be rec_date
later when displaying the graph with chart.js. Since the request is in JSON format, format.json
is executed and the search results are returned in JSON format. If it is difficult to understand, try debugging with binding.pry
etc. and it will be easier to get an image.
Let's go back to the js file again and look at the drawing process.
app/javascript/packs/chart_sample/chart_user_height.js (3)
//Receive request from ajax
.done(function (data) {
var height_val = [];
var height_name = [];
var height_date = [];
// chart.Store in an array for passing to js
$(data).each(function(index, height) {
height_name.push(height.name);
height_val.push(height.height);
height_date.push(height.rec_date);
});
chart_func.bar_chart(document, 'myChart', "height", height_date, height_val);
})
}
})
});
});
Here, the JSON format received from the model is converted to an array type in order to pass it to chart.js. For example, height_val
is an array of Takashi-kun's past heights such as [(height), (height), (height)]. (I think there is a better way to write it a little more clearly ...)
Then, pass it to the self-made function that reads the array containing the date data and height data. The self-made function instantiates Chart with chart.js
. The argument passed to the function is chart_func.bar_chart (document, id name of canvas tag, label name to be attached to graph (optional), array of horizontal axis data, array of vertical axis data)
.
app/javascript/packs/origin_func.js
exports.bar_chart = function (document, id_name, label_name, data_x, data_y) {
var elm = document.getElementById(id_name).getContext('2d');
//Delete the instance if the chart is already drawn
if(myChart.constructor === Chart){
myChart.destroy();
};
//Depiction of bar graph
myChart = new Chart(elm, {
type: 'bar',
data: {
labels: data_x,
datasets: [{
label: label_name,
data: data_y,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
})
};
if(myChart.constructor === Chart){
myChart.destroy();
};
If the canvas is reused, the graph will be overlaid on the previous graph, so if an instance of Chart
has already been created, use Chart.destroy
for the description here. This is because it needs to be deleted. myChart.constructor
will be Chart
when an instance is created from HTMLCanvasElement
at the time of loading.
The rest is creating a Chart instance based on the array data.
That's all for the implementation.
I explained chart_user_height.js
intermittently, so I will paste it below.
app/javascript/packs/chart_sample/chart_user_height.js (collectively)
$(document).on('turbolinks:load', function () {
$(function () {
//Load your own function for chart display
var chart_func = require("../origin_func.js")
$('#area').change(function() {
var selected_name = $('option:selected').text();
var selected_index = $('option:selected').val();
if (selected_index > 0) {
$("h1").css("color", "blue");
//Request the value of SelectBox in json format using ajax
// messages/The index action of the searches controller receives
$.ajax({
type: 'GET', //Request type
url: '/chart_sample/search', //URL to send the request
data: { name: selected_name }, //Data to send to the server
dataType: 'json' //Type returned from the server
})
//Receive request from ajax
.done(function (data) {
var height_val = [];
var height_name = [];
var height_date = [];
// chart.Store in an array for passing to js
$(data).each(function(index, height) {
height_name.push(height.name);
height_val.push(height.height);
height_date.push(height.rec_date);
});
chart_func.bar_chart(document, 'myChart', "height", height_date, height_val);
})
}
})
});
});
If you have any questions, please feel free to comment. In the future, I would like to add a graph representation and a save function. Thank you for staying with us so far!
Recommended Posts