I have tried making the data according to #wifis (based on mac_id) is generated but currently the data is identical with the following code -
Controller:
class DashboardsController < ApplicationController
before_action :authenticate_user!
def show
#wifis = Wifi.where(user_id: current_user.id)
pdaily_number_of_logins_data = []
phourly_total_traffic_data = []
pper_user_monthly_traffic_data = []
#wifis.each do |wifi|
daily_number_of_logins_data = Radacct.fetch("SELECT gd_day(acctstarttime, 'UTC') AS date, COUNT(*) AS count FROM radacct WHERE (`calledstationid` = ?) AND (`acctstarttime` >= ?) GROUP BY date", wifi.mac_id, 1.month.ago)
pdaily_number_of_logins_data += daily_number_of_logins_data.to_a if daily_number_of_logins_data.to_a
#daily_number_of_logins = pdaily_number_of_logins_data.collect{|i| [i[:date],i[:count]]}
hourly_total_traffic_data = Radacct.fetch("SELECT gd_hour_of_day(acctstarttime, 'UTC') AS hour_of_day, ROUND(((SUM(acctinputoctets)+SUM(acctoutputoctets))/1049000)) AS totaltraffic FROM radacct WHERE (`calledstationid` = ?) AND (`acctstarttime` >= ?) GROUP BY hour_of_day", wifi.mac_id, 1.day.ago)
phourly_total_traffic_data += hourly_total_traffic_data.to_a if hourly_total_traffic_data.to_a
#hourly_total_traffic = phourly_total_traffic_data.collect{|i| [i[:hour_of_day],i[:totaltraffic]]}
per_user_monthly_traffic_data = Radacct.fetch("SELECT username, ROUND(((SUM(acctinputoctets)+SUM(acctoutputoctets))/1049000)) AS `traffic` FROM `radacct` WHERE (`calledstationid` = ?) AND (`acctstarttime` >= ?) GROUP BY username", wifi.mac_id, 1.month.ago)
pper_user_monthly_traffic_data += per_user_monthly_traffic_data.to_a if per_user_monthly_traffic_data.to_a
#per_user_monthly_traffic = pper_user_monthly_traffic_data.collect{|i| [i[:username],i[:traffic]]}
end
end
end
and View:
% #wifis.each do |wifi| %>
<h1><%= wifi.mac_id %></h1>
<%= line_chart #daily_number_of_logins, { discrete: true, library: {hAxis: {title: "Date"}, vAxis: {title: "Number of Logins (daily)"}}} %>
<%= column_chart #hourly_total_traffic, {library: {hAxis: {title: "Hour"}, vAxis: {title: "Traffic in Megabytes (hourly)"}}} %>
<%= pie_chart #per_user_monthly_traffic, discrete: true %>
<% end %>
i have tried the above based on this answer but the problem that i am having is #wifi object is used in both controller and views: Loop within Loop in Rails Controller
The problem is that loop in your controller action runs and overwrites the instance variables on each iteration. So only the last iteration remains. If you wanted to save data for each wifi, you need another data structure, not plain ivars. Perhaps a hash where wifi is the key.
#counters = {}
#wifis.each do |wifi|
#counters[wifi] ||= {}
#counters[wifi][:daily_number_of_logins] = ...
Then in the view
<% #wifis.each do |wifi| %>
<%= line_chart #counters[wifi][:daily_number_of_logins] %>
<% end %>
Related
I'm trying to paginate some results using the will_paginate gem in Ruby on Rails. The thing is the results are non Active Records so I follow the steps here: https://www.rubydoc.info/github/mislav/will_paginate/WillPaginate/Collection
to be able to do that, but the problem is that now I'm just able to see the results for the first page, the next pages are completely empty. I verified that the query has results for the next pages and everything looks good.
This is the code I wrote, any idea guys. Thanks!
I attached some pictures to show you guys how looks like, one is from the first page results and the other is from the second page results.
# controller AssetController
require Rails.root.to_s + '/config/initializers/will_paginate_array'
class AssetController < ApplicationController
before_action :require_login
def index
#search = params[:search]
#assetType = params[:assetType]
#searchBy = params[:searchBy]
limit = 30
currentPage = params[:page];
if currentPage == nil
currentPage = 1
end
offset = (currentPage.to_i - 1) * limit
count = Assets.getAssetsCount()
results = Assets.getAllAssets(offset, limit)
if results.class == Array
#assets = results.paginate_custom_array(currentPage, limit, count)
else
# TODO
end
end
# config/initializers/will_paginate_array.rb
require 'will_paginate/collection'
Array.class_eval do
def paginate_custom_array(page = 1, per_page = 15, size)
WillPaginate::Collection.create(page, per_page, size) do |pager|
pager.replace self[pager.offset, pager.per_page].to_a
end
end
end
# views/asset/index.erb
<div id="assets_results">
<%= render 'partials/assets_result' %>
</div>
# views/asset/index.js.erb
$("#assets_results").html("<%= escape_javascript render("partials/assets_result") %>");
$('#paginator').html('<%= escape_javascript(will_paginate(#assets, :remote => true).to_s) %>');
# views/partial/_assets_result.html.erb
<% #assets.each do |asset| %>
<tr>
<td>
...
</td>
</tr>
<% end %>
<div class="text-center">
<div id="paginator"class="pagination pagination-lg">
<%= will_paginate #assets, :remote => true %>
</div>
</div>
You are applying pagination logic twice.
First, you select only one page of results from your Assets.getAllAssets method:
count = Assets.getAssetsCount()
results = Assets.getAllAssets(offset, limit)
Then, you pass that single page of 30 records into will_paginate's own pagination methods, which cannot show you results 31..60 if you only give it a single page of 30 results.
You should either drop your will_paginate logic, or change your getAllAssets method to return something like an ActiveRecord::Relation that can have a limit/offset applied to it by will_paginate.
My problem is that I don't know how to add different buttons that remain in a condition using the gem for server side processing ajax-datatables-rails. For example before trying to do sever side processing I had this in my view.
<% if current_user.sales_manager? || current_user.admin? %>
<td>
<%= link_to t('.destroy', :default => t("helpers.links.destroy")),
bill_sale_path(bill_sale),
:method => :delete %>
</td>
<% end %>
and following the tutorial in the main page of the gem, in bill_sale_datatable.rb I have this.
def data
records.map do |record|
[
link_to('Show', bill_sale_path(record), class: 'btn-xs btn-link'),
record.customer.name,
record.seller.name,
l(record.date_sold, format: :short),
record.payment_type.name,
record.payed,
number_to_currency(record.total),
CONDITION AND BUTTON HERE
]
end
end
Then, how do I use the server side processing to provide different buttons that belongs to an if condition?
While I haven't used the gem, I have used datatables with Rails and this is what I did:
Store the button as a variable before the array and then just call the variable in the array.
records.map do |record|
record_button = ''
record_button = button_to('A', button1_path) if condition1
record_button = button_to('B', button2_path) if condition2
record_button = button_to('C', button3_path) if condition3
record_button = button_to('D', button4_path) if condition4
[
link_to('Show', bill_sale_path(record), class: 'btn-xs btn-link'),
record.customer.name,
record.seller.name,
l(record.date_sold, format: :short),
record.payment_type.name,
record.payed,
number_to_currency(record.total),
record_button
]
end
You could also use a case statement if that suited your needs.
Make sure you add
def_delegator :#view, :button_to
To the top of your file as per:
https://github.com/jbox-web/ajax-datatables-rails#using-view-helpers
I am trying to make the hashtags within a string into links.
e.g. I'd like a string that's currently: "I'm a string which contains a #hashtag" to transform into: "I'm a string which contains #hashtag"
The code that I have at the moment is as follows:
<% #messages.each do |message| %>
<% string = message.content %>
<% hashtaglinks = string.scan(/#(\d*)/).flatten %>
<% hashtaglinks.each do |tag| %>
<li><%= string = string.gsub(/##{tag}\b/, link_to("google", "##{tag}") %><li>
<% end %>
<% end %>
I've been trying (in vain) for several hours to get this to work, reading through many similar stackoverflow threads- but frustration has got the better of me, and as a beginner rubyist, I'd be really appreciate it if someone could please help me out!
The code in my 'server.rb' is as follows:
get '/' do
#messages = Message.all
erb :index
end
post '/messages' do
content = params["content"]
hashtags = params["content"].scan(/#\w+/).flatten.map{|hashtag|
Hashtag.first_or_create(:text => hashtag)}
Message.create(:content => content, :hashtags => hashtags)
redirect to('/')
end
get '/hashtags/:text' do
hashtag = Hashtag.first(:text => params[:text])
#messages = hashtag ? hashtag.messages : []
erb :index
end
helpers do
def link_to(url,text=url,opts={})
attributes = ""
opts.each { |key,value| attributes << key.to_s << "=\"" << value << "\" "}
"<a href=\"#{url}\" #{attributes}>#{text}</a>"
end
end
Here is the code to get you started. This should replace (in-place) the hashtags in the string with the links:
<% string.gsub!(/#\w+/) do |tag| %>
<% link_to("##{tag}", url_you_want_to_replace_hashtag_with) %>
<% end %>
You may need to use html_safe on the string to display it afterwards.
The regex doesn't account for more complex cases, like what do you do in case of ##tag0 or #tag1#tag2. Should tag0 and tag2 be considered hashtags? Also, you may want to change \w to something like [a-zA-Z0-9] if you want to limit the tags to alphanumerics and digits only.
I'm trying to set all the values to 0 but the 3rd line (send(x)) is giving me problems. Seems right to me, but doesn't work. x is the car and name of the columns in Power. Any tips?
<% #cars.each do |x| %>
<% #power = Power.find_by_user_id(#user) %>
<% #power.send(x) = 0 %>
<% #power.save %>
<% end %>
Assuming #cars contains column names of Power, you need to send the setter method (i.e. with an = at the end). You also need to ensure you're passing a symbol to send.
#cars.each do |x|
#power = Power.find_by_user_id(#user)
#power.send(:"#{x}=", 0)
#power.save
end
There's also not an obvious reason why you need to set or save #power in the loop, so it might be better as:
#power = Power.find_by_user_id(#user)
#cars.each do |x|
#power.send(:"#{x}=", 0)
end
#power.save
I have a model called event_recurrences it contains 2 important columns event_id and cached_schedule
cached_schedule contains an array of dates
event_id is used to reference the event
I need to
Get all the event_recurrence objects #something.event_recurrences - Done
Go through each recurrence object and get the event_id and all the
dates from cached_schedule
Iterate through each month, and spit out a list like the following
Jan
event_id date
event_id date
event_id date
Feb
event_id date
... and so on
To recap the event_id is located event_recurrence.event_id the dates that the event_id will happen on are located in an array inside event_recurrence.cached_schedule
Some I have some incomplete code to work with...
This code works successfully to show each event_recurrence object by month using the created_at field.
in my controller
#schedule_months = #something.event_recurrences.order("created_at DESC").group_by { |e| e.created_at.beginning_of_month }
in my view
<% #schedule_months.keys.sort.each do |month| %>
<div class="month">
<%= month.strftime("%B %Y") %>
</div>
<% for event in #schedule_months[month] %>
<li><%= event %></li>
<% end %>
<% end %>
Thanks in advance.
Sincerely, jBeas
There are some details missing from your question... for example, can the dates in cached_schedule span multiple months, or are they all guaranteed to be in the same month?
If you just want to use core Ruby:
dates = []
#something.event_recurrences.each do |er|
er.cached_schedule.each { |date| dates << [date, er.event_id] }
end
#event_dates = dates.group_by { |(date,event_id)| date.mon }
Then in the view:
<% #event_dates.keys.sort.each do |month| %>
<div class="month"> <%= month.strftime("%B %Y") %></div>
<% #event_dates[month].each do |(date,event_id)| %>
<li><%= date %> <%= event_id %></li>
<% end %>
<% end %>
You may have to adjust the code a little depending on the specifics, but this should give you the idea. Note the use of destructuring assignment: #event_dates[month].each do |(date,event_id)|. This saves a line of code and expresses what the code is doing more clearly.
If you don't mind adding your own extensions to the core Ruby classes, you could make this code even cleaner and more consise. I often use a method which I call mappend:
module Enumerable
def mappend
result = []
each { |a| enum = yield a; enum.each { |b| result << b } if enum }
result
end
end
The name is a mix of map and append -- it is like map, but it expects the return value of the mapping block to also be Enumerable, and it "appends" all the returned Enumerables into a single Array. With this, you could write:
#event_dates = #something.event_recurrences.mappend { |er| er.cached_schedule.map { |date| [date, er.event_id] }}.group_by { |(date,event_id)| date.mon }
OK, that might be a lot for one line, but you get the idea: it saves you from using an intermediate variable to accumulate results.
UPDATE: Something like mappend is now part of the Ruby core library! It's called flat_map.