L.D L.D - 6 months ago 10
Javascript Question

Rails how to get @products in the controller to be passed to another Java Script

I am getting my products index from another custom developed class which is passed to the

index.html.erb
for rendering in a table format, using
DataTables
and
JavaScript
in the
index.html.erb
page. This code is woking very well so far, doing
pagination
,
sorting
and
filtering
on the
server side
, but now I want to get a
@products
variable from the
JSON
used by
DataTables
which I want to process it in the
ProductsController
before it is passed as a
@hash
to another
JavaScript
eventualy to render the
@markers
of the
@products
on a
Google Map
.

Here is my code:

products_controller.rb


...
def index
respond_to do |format|
format.html
format.json { render json: ProductsDatatable.new(view_context) }
end
end
...


index.html.erb


<div class="container-fluid">
<h1>Products</h1>

<table id="products" width="100%" class="display cell-border compact hover order-column row-border stripe" data-source="<%= products_url(format: "json") %>">
<thead>
<tr>
<th style="text-align: center">Product ID</th>
<th style="text-align: center">Product Name</th>
<th style="text-align: center">Category</th>
<th style="text-align: center">Release Date</th>
<th style="text-align: center">Price</th>
<th style="text-align: center">Created At</th>
<th style="text-align: center">Updated At</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>

<script>
$(document).ready(function() {
$('#products').dataTable({
sPaginationType: "full_numbers",
bJQueryUI: true,
bProcessing: true,
bServerSide: true,
sAjaxSource: $('#products').data('source'),
sDom: 'CRlfrtip',
bStateSave: true,
responsive: true
})
} );
</script>

Custom class fetching the records from server with pagination, sorting and filtering.

`/datatables/products_datatables.rb`

class ProductsDatatable
delegate :params, :link_to, :number_to_currency, to: :@view

def initialize(view)
@view = view
end

def as_json(options = {})
{
sEcho: params[:sEcho].to_i,
iTotalRecords: Product.count,
iTotalDisplayRecords: products.total_entries,
aaData: data
}
end

private

def data
products.map do |product|
[
link_to(product.id, product),
product.product_name,
product.category,
product.release_date.strftime("%Y-%m-%d"),
number_to_currency(product.price),
product.created_at.strftime("%Y-%m-%d %I:%M%p"),
product.updated_at.strftime("%Y-%m-%d %I:%M%p")
]
end
end

def products
@products ||= fetch_products
end

def fetch_products #this version genertes more optimized queries for the db
if params[:sSearch].present?
products = Product
.where("product_name like :search
or category like :search
or date_format(release_date, '%Y-%m-%d') like :search
", search: "%#{params[:sSearch]}%"
)
.order("#{sort_by}")
.page(page).per_page(per_page)
else
products = Product
.order("#{sort_by}")
.page(page).per_page(per_page)
end
products
end

def page
params[:iDisplayStart].to_i/per_page + 1
end

def per_page
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
end

def sort_by
columns = %W[id product_name category release_date price created_at updated_at]
s = String.new
if params[:iSortCol_0].present?
s = s + "," + columns[params[:iSortCol_0].to_i] + " " + sort_direction(params[:sSortDir_0])
end
if params[:iSortCol_1].present?
s = s + "," + columns[params[:iSortCol_1].to_i] + " " + sort_direction(params[:sSortDir_1])
end
if params[:iSortCol_2].present?
s = s + "," + columns[params[:iSortCol_2].to_i] + " " + sort_direction(params[:sSortDir_2])
end
if params[:iSortCol_3].present?
s = s + "," + columns[params[:iSortCol_3].to_i] + " " + sort_direction(params[:sSortDir_3])
end
if params[:iSortCol_4].present?
s = s + "," + columns[params[:iSortCol_4].to_i] + " " + sort_direction(params[:sSortDir_4])
end
if s.empty?
s = columns[params[:iSortCol_0].to_i] + " " + sort_direction(params[:sSortDir_0])
end
if s[0] == ","
s.slice!(0)
end
s
end

def sort_direction (n)
n == "desc" ? "desc" : "asc"
end
end


How i can get the
@products
in the controller, such a way when user navigates between the pages index pages, to have the content of
@products
changed accordingly?

L.D L.D
Answer

Here is the kind of solution I was expecting.

In the controller, one single line of code:

@json = ProductsDatatable.new(view_context).as_json

This makes data available for further processing like this example below.

You can display the entire JSON object:

<%= @json %>

And slice and dice as wished this json object further.

Total Records Count: <%= @json[:iTotalRecords] %>
aaData class: <%= @json[:aaData].class %>
aaData count: <%= @json[:aaData].count %>
aaData first class: <%= @json[:aaData].first.class %>
aaData first content: <%= @json[:aaData].first %>
aaData first content product Product ID (link): <%= @json[:aaData].first[0] %>
aaData first content product Product Name: <%= @json[:aaData].first[1] %> 

The problem now is that now when the page is changed only the firs 10 records are visible not the current 10 records from page 5, 7, 10, etc.