L.D L.D - 2 years ago 71
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 Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download