If i change the processing from client-side to server-side, i will get all information for the table, but I can't search and sort the columns. But its possible to go to the next page. I have only 2 columns for searching and sorting to test it. Hopefully you can help me.
Database:
t.text "comment"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "source_stock_id"
t.integer "destination_stock_id"
t.integer "order_id"
js.coffee-Code:
jQuery ->
$("#product_relocates_table").dataTable
bProcessing: true
bServerSide: true
sAjaxSource: $('#product_relocates_table').data('source')
"aaSorting": [[ 0, "desc" ]]
Datatable-Code:
class ProductRelocatesDatatable
delegate :params, :h, :link_to, to: :#view
def initialize(view)
#view = view
end
def as_json(options = {})
{
sEcho: params[:sEcho].to_i,
iTotalRecords: ProductRelocate.count,
iTotalDisplayRecords: product_relocates.total_count,
aaData: data
}
end
private
def data
product_relocates.map do |product_relocate|
[
h(product_relocate.created_at),
h(product_relocate.comment),
h(product_relocate.source_stock),
h(product_relocate.destination_stock),
h(product_relocate.quantity),
link_to('Show', [:admin, product_relocate])
]
end
end
def product_relocates
#product_relocates ||= fetch_product_relocates
end
def fetch_product_relocates
product_relocates = ProductRelocate.order("#{sort_column} #{sort_direction}")
product_relocates = product_relocates.page(page).per(per)
if params[:sSearch].present?
search_string = search_columns.map do |search_column|
"#{search_column} like :search"
end.join(" OR ")
product_relocates = product_relocates.where(search_string, search: "%#{params[:sSearch]}%")
end
product_relocates
end
def page
params[:iDisplayStart].to_i/per + 1
end
def per
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
end
def search_columns
%w[product_relocates.created_at product_relocates.comment]
end
def sort_columns
%w[product_relocates.created_at product_relocates.comment]
end
def sort_column
sort_columns[params[:iSortCol_0].to_i]
end
def sort_direction
params[:sSortDir_0] == "desc" ? "desc" : "asc"
end
end
I refactored a superclass that handles server side multi-column searching and sorting:
https://gist.github.com/2936095
which is derived from:
http://railscasts.com/episodes/340-datatables
class Datatable
delegate :params, :h, :raw, :link_to, :number_to_currency, to: :#view
def initialize(klass,view)
#klass = klass
#view = view
end
def as_json(options = {})
{
sEcho: params[:sEcho].to_i,
iTotalRecords: #klass.count,
iTotalDisplayRecords: items.total_entries,
aaData: data
}
end
private
def data
[]
end
def items
#items ||= fetch_items
end
def fetch_items
items = filtered_list
items = selected_columns(items)
items = items.order(sort_order)
items = items.page(page).per_page(per_page)
if params[:sSearch].present?
items = items.where(quick_search)
end
items
end
def filtered_list
#klass.all
end
def selected_columns items
items
end
def quick_search
search_for = params[:sSearch].split(' ')
terms = {}
which_one = -1
criteria = search_for.inject([]) do |criteria,atom|
which_one += 1
terms["search#{which_one}".to_sym] = "%#{atom}%"
criteria << "(#{search_cols.map{|col| "#{col} like :search#{which_one}"}.join(' or ')})"
end.join(' and ')
[criteria, terms]
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 columns
[]
end
def sort_order
colnum = 0
sort_by = []
while true
break if !sorted?(colnum)
sort_by << "#{sort_column(colnum)} #{sort_direction(colnum)}"
colnum += 1
end
sort_by.join(", ")
end
def sorted? index=0
!params["iSortCol_#{index}"].nil?
end
def sort_column index=0
index = "iSortCol_#{index}"
columns[params[index].to_i]
end
def sort_direction index=0
index = "sSortDir_#{index}"
params[index] == "desc" ? "desc" : "asc"
end
end
Related
Can you help me? I dont understand how to do it.
How to calculate TOTAL PRICE when i created the room?
I am dont understand how to do it right.
Here is my code:
room_controller.rb
def create
parameters = room_params.to_hash
parameters[:created_by] = #current_user.id
parameters[:account_id] = #current_user.account_id
#room = #section.rooms.create!(parameters)
update_room(#room, params)
end
...
def update
params = room_params.to_hash
update_room(#room, params)
json_response(#room)
end
def update_room(room, json)
return unless room
unless json.key?('total_price')
if json.key?('price') || json.key?('square')
square = json.key?('square') ? json['square'].to_f : room.square
price = json.key?('price') ? json['price'].to_f : room.price
json['total_price'] = price * square
end
end
unless json.key?('price')
if json.key?('total_price') || json.key?('square')
square = json.key?('square') ? json['square'].to_f : room.square
total_price = json.key?('total_price') ? json['total_price'].to_f : room.total_price
json['price'] = total_price / square
end
end
room.update(json)
end
def room_params
params.permit(
:level, :square, :total_price, :price, :number, :room_type,
:plan_image, :plan_coordinate, :view_image, :interior_image,
:rooms_count, :status, :marked
)
end
schema.rb
create_table "rooms", force: :cascade do |t|
...
t.float "square", default: 0.0
t.float "price", default: 0.0
t.float "total_price", default: 0.0
If total_price is square multiplied by price you can do that in the model.
class Room
before_save :calculate_total
private
def calculate_total
self.total_price = square * price
end
end
In my view I have
<h4><%= number_to_currency #grand_total, precision: 0, unit: "EUR ", separator: "," %></h4>
This shows a correct total for a column. #grand_total is defined in my controller and it's the sum of total defined in model.
My model
class Ticketline < ActiveRecord::Base
belongs_to :ticket, :foreign_key => 'TICKET'
belongs_to :product, :foreign_key => 'PRODUCT'
def discount
(self.AMOUNT - self.TOTAL)
end
def total_amount
( pricesell = self.try(:PRICESELL) || 0
units = self.try(:UNITS) || 0
pricesell * units)
end
def total
(
price = self.try(:PRICE) || 0
units = self.UNITS || 0
price * units)
end
def consignor_cost
cost = product.location.try(:DISCOUNT_CONSIGNOR) || 0
cost ? (self.total * cost) : 0
end
def cost_of_goods_sold
cost = product.PRICEBUY || 0
cost ? (cost * self.TOTALUNITS) : 0
end
def gross_profit
(self.total - self.consignor_cost - self.cost_of_goods_sold)
end
class ProductSale < Ticketline
end
end
My controller
class ProductSalesController < TicketlinesController
def index
params.permit!
#q = Ticketline.joins(:product, :product => :location).group(:PRODUCT, :TICKET, :DISCOUNT_CONSIGNOR).select("PRODUCT, DISCOUNT_CONSIGNOR, UNITS, TICKET, SUM(ticketlines.PRICESELL*UNITS) AS AMOUNT, SUM(PRICE*UNITS) AS TOTAL, PRICE, UNITS, ticketlines.PRICESELL, SUM(UNITS) AS TOTALUNITS").ransack(params[:q])
#product_sales = #q.result.paginate(:page => params[:page], :per_page => 30)
#product_salesnp = #q.result
#amount_total = #q.result.map(&:total_amount).sum
#discount_total = #q.result.map(&:discount).sum
#grand_total = #q.result.map(&:total).sum
#consignor_cost_total = #q.result.map(&:consignor_cost).sum
#cost_of_goods_sold_total = #q.result.map(&:cost_of_goods_sold).sum
#gross_profit_total = #q.result.map(&:gross_profit).sum
respond_to do |format|
format.html
format.pdf do
pdf = SalesByProductPdf.new(#product_salesnp)
pdf.render_file "report.pdf"
send_data pdf.render, filename: 'report.pdf', type: 'application/pdf', disposition: 'inline'
end
end
end
end
On the pdf generated by prawn I want to show the same so I tried to enter on the corresponding pdf.rb file:
class SalesByProductPdf < Prawn::Document
include ActionView::Helpers::NumberHelper
def initialize(product_sales)
super()
#product_sales = product_sales
header
text_content
table_content
footer
end
def header
#something
end
def text_content
#something
end
def table_content
#something
end
def footer
text number_to_currency(grand_total, precision: 0, unit: "EUR ", separator: ",")
end
end
which gives me no error but shows no value.
What is the correct syntax?
You can explicitly include the ActionView::Helpers::NumberHelper module or whatever module you want in your prawn file.
Try passing in the #grand_total instance variable in your pdf file's initialize method:
class SalesByProductPdf < Prawn::Document
include ActionView::Helpers::NumberHelper
def initialize(product_salesnp, grand_total)
super()
#product_salesnp = product_salesnp
#grand_total = grand_total
header
text_content
table_content
footer
end
...
def footer
text number_to_currency(#grand_total, precision: 0, unit: "EUR ", separator: ",")
end
end
And pass in #grand_total in your controller too when you create a new Pdf object:
format.pdf do
pdf = SalesByProductPdf.new(#product_salesnp, #grand_total)
pdf.render_file "report.pdf"
send_data pdf.render, filename: 'report.pdf', type: 'application/pdf', disposition: 'inline'
end
Hopefully that should work..
this is the schema and my model for Visit (visit's status can be: Confirmed, Current, Expired and To be approved)
schema.rb
create_table "visits", force: true do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.date "start"
t.date "end"
t.integer "idVisit"
t.integer "employee_id"
t.integer "visitor_id"
t.string "status", default: "Confirmed"
end
Visit.rb
class Visit < ActiveRecord::Base
belongs_to :employee
belongs_to :visitor
default_scope -> { order(:created_at) }
validates :start, presence: true, uniqueness: {scope: [:end, :visitor_id]}
validates :end, presence: true
validates :visitor_id, presence: true
validates :employee_id, presence: true
validate :valid_date_range_required
def valid_date_range_required
if (start && end) && (end < start)
errors.add(:end, "must be after start")
end
end
end
Now my problem is that I need to compare for each visit, after each time I do show action in employees_controller.rb, the start and end date to Date.today (except for To be approved status); according to it I will change the status of visits in the database.
Here is what I did but probably there will be some mistakes since for now an error occurs at least, so I hope you could help me to fix it.
In Visit.rb I created this:
def check_visit_status(visit)
if visit.status != 'To be confirmed'
if visit.start <= Date.today && visit.end >= Date.today
visit.status = 'Current'
end
if visit.end < Date.today
visit.status = 'Expired'
end
end
end
Now in employees_controller.rb I have (I won't post it all):
class EmployeesController < ApplicationController
after_action :update_status, only: :show
def show
if logged_in?
#employee = Employee.find(params[:id])
#indirizzimac = current_employee.indirizzimacs.new
#visitor = current_employee.visitors.new
#visit = current_employee.visits.new
#visits = current_employee.visits.all
if params[:act]=='myData'
render 'myData'
elsif params[:act]=='myNetwork'
render 'myNetwork'
elsif params[:act]=='temporaryUsers'
render 'temporaryUsers'
elsif params[:act]=='guestsVisits'
render 'guestsVisits'
elsif params[:act]=='myAccount'
render 'myAccount'
else
render 'show'
end
else
render 'static_pages/errorPage'
end
end
def update_status
if #visits.any?
#visits.each do |visit|
check_visit_status(visit)
end
end
end
end
Thank you a lot in advance
I really have to thank eeeeeean for his immense help.
I figured out my problem so I want to post here my solution in order to help someone looking for the same thing I was asking for.
employees_controller.rb
class EmployeesController < ApplicationController
after_action :update_status, only: :show
def show
[...]
end
def update_status
if #visits.any?
#visits.each do |visit|
visit.check_visit_status
end
end
end
end
Visit.rb
def check_visit_status
if self.status != 'To be confirmed'
if self.start <= Date.today && self.end >= Date.today
self.update_attribute :status, 'Current'
end
if self.end < Date.today
self.update_attribute :status, 'Expired'
end
end
end
You need to call check_visit_status on an instance of Visit, but right now it's being called on self, which in this scope refers to the employees controller. Try this:
visit.rb
def check_visit_status
if self.status != 'To be confirmed'
if self.start <= Date.today && end >= Date.today
self.status = 'Current'
end
if self.end < Date.today
self.status = 'Expired'
end
end
end
Then call it like this:
employees_controller.rb
#visits.each do |visit|
visit.check_visit_status
end
That should get you out of that particular error.
I'm receiving a JSON object and nested array via a Rails 4 api with params like so:
{
"token" => "123"
"lessons" => [
{
"token_id" => "j12l3n123",
"attr_1" => "hello",
"attr_2" = "is it me you're looking for"
},
{
"token_id" => "j12l",
"attr_1" => "Nope",
"attr_3" = "You're not."
}
]
}
And I have a controller like so:
def update_all
#fetch collection with one db hit
token_ids = params[:lessons].map{|l| l[:token_id]}
#lessons = Lesson.where(token_id: token_ids)
params[:lessons].each do |l|
lesson = #lessons.detect { |lesson| lesson.token_id == l[:token_id] }
# How do I update the record with strong params?
lesson.update_attributes(lesson_params)
end
end
private
def lesson_params
params.permit(
:attr_1,
:attr_2,
:attr_3
)
end
How do i update each record with the right object in the array, and use strong parameters to do so?
def update_all
lesson_params.each do |l|
lesson = Lesson.where(token_id: l[:token_id]).first
lesson.update_attributes(l)
end
end
private
def lesson_params
params.require(:lessons).map do |l|
ActionController::Parameters.new(l.to_hash).permit(
:attr_1,
:attr_2,
:attr_3
)
end
end
def lesson_params
params.permit(:token, lessons: [:token_id, :attr_1, :attr_2, :attr_3 ])
end
in Controller something like following
def update_all
lesson_params[:lessons].each do |lesson_param|
lesson = Lesson.find(lesson_param[:token_id])
lesson.update_attributes(lesson_param)
end
end
This is my first time using dataTables. I want to be able to display the records in my Projects table and sort by each field. I'm following this RailCast and used the code provided by them. However, my page loads without errors but the actual records are never loaded into the table--it just says "Processing..." indefinitely. Any ideas what would cause this? Some of my code:
view/projects/new.html.erb (where the index of my application points to, and where I want the table displayed)
<table id="projects" class="display" data-source="<%= projects_url(format: "json") %>">
<thead>
<tr>
<th>File</th>
<th>Author</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
projects.js.coffee
jQuery ->
$("#projects").dataTable
bProcessing: true
bServerSide: true
sAjaxSource: $('#projects').data('source')
"aaSorting": [[ 0, "desc" ]]
projects controller
# GET /projects/new
# GET /projects/new.json
def new
#projects = Project.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: ProjectsDatatable.new(view_context) }
end
end
Projects_datatable.rb
class ProjectsDatatable
delegate :params, :h, :link_to, :number_to_currency, to: :#view
def initialize(view)
#view = view
end
def as_json(options = {})
{
sEcho: params[:sEcho].to_i,
iTotalRecords: Project.count,
iTotalDisplayRecords: Project.count,
aaData: data
}
end
private
def data
projects.map do |proj|
[
h(proj.filename),
h(proj.author)
]
end
end
def projects
#projects ||= fetch_projects
end
def fetch_projects
projects = Project.order("#{sort_column} #{sort_direction}")
projects = projects.page(page).per_page(per_page)
if params[:sSearch].present?
projects = projects.where("name like :search or category like :search", search: "%#{params[:sSearch]}%")
end
projects
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_column
columns = %w[name category released_on price]
columns[params[:iSortCol_0].to_i]
end
def sort_direction
params[:sSortDir_0] == "desc" ? "desc" : "asc"
end
end
And my projects migration:
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :filename
t.string :location
t.string :author
end
end
end
If anyone has any input I'd be so grateful. thanks.
The answer is certainly a bit late but i can see some mistakes at those lines :
projects = projects.where("name like :search or category like :search", search: "%#{params[:sSearch]}%")
and
columns = %w[name category released_on price]
You have to replace those fields by filename, location, author.
iTotalDisplayRecords: Project.count,
is also wrong, replace it with
iTotalDisplayRecords: projects.total_entries,
Be sure that you have will_paginate