I try to fetch random single database from rails by ajax? - ruby-on-rails

I am using ajax with rails to get single random row I want to display just 10 rows with every request by ajax get one single random and display it, i try something like that, Model.all.sample or Using offset with first but my problem is duplication how can avoid it or how can i set all response to check if I sent it before or not Note: I send all elements was appended as array for backend to check if i send it before and change it but i have wrong
result
my code is :- in backend is my function
def get_10
arr = params['arr']
if arr.nil?
#rand_record = Phrase.all.sample
else
i = 0
if i < 10
#rand_record = Phrase.all.sample
while(i < arr.length) && (i<10)
flag = arr[i].include?#rand_record.name
if flag
#rand_record = Phrase.all.sample
i = 0
elsif flag == false
return #rand_record
end
i+=1
end
end
end
respond_to do |format|
format.js { }
end
end
in my js ajax is :
function myFunction(){
var arr = []
var len = $('li').length
for (let i=0 ; i< len; i++){
var attr = $('li')[i].childNodes['0'].data
arr.push(attr)
}
$.ajax({
method: 'GET',
url: '/phrase',
dataType: 'script',
data: {arr: arr}
}).done(function(data){
console.log(data);
})
}
in template is:
<div class="form-group">
<%= button_tag 'GetPhrases', type: 'button', onclick:"myFunction()", class: 'btn btn-default' , id:"get" %>
</div>
my result is
this pharase number 1
this pharase number 5
this pharase number 4
this pharase number 5
this pharase number 8
enter image description here
I want to avoid duplication I want to retrive just 10 random single row without duplication

Be careful with sample on the active record relation, instead do:
Model.where(id: Model.all.pluck(:id).sample(10))
This will just pluck all the IDs and sample 10 of them and then select records with those random 10 ids.

Related

How to calculate specific rating count hash in ruby on rails?

So, I have an after_save hook on review model which calls calculate_specific_rating function of product model. The function goes like this:
def calculate_specific_rating
ratings = reviews.reload.all.pluck(:rating)
specific_rating = Hash.new(0)
ratings.each { |rating| specific_rating[rating] += 1 }
self.specific_rating = specific_rating
save
end
Right now, it returns
specific_rating => {
"2"=> 3, "4"=> 1
}
I want it to return like:
specific_rating => {
"1"=> 0, "2"=>3, "3"=>0, "4"=>1, "5"=>0
}
Also, is it okay to initialize a new hash everytime a review is saved? I want some alternative. Thanks
You can create a range from 1 until the maximum value in ratings plus 1 and start iterating through it, yielding an array where the first element is the current one, and the second element is the total of times the current element is present in ratings. After everything the result is converted to a hash:
self.specific_rating = (1..ratings.max + 1).to_h { |e| [e.to_s, ratings.count(e)] }
save
You could also do something like this -
def calculate_specific_rating
ratings = [1,2,3,4,5]
existing_ratings = reviews.group_by(&:rating).map{|k,v| [k, v.count]}.to_h
Hash[(ratings - existing_ratings.keys).map {|x| [x, 0]}].merge(existing_ratings)
end
which gives
{3=>0, 4=>0, 5=>0, 2=>3, 1=>1}

Adding values to a hash within/over multiple each loops

I have a concept called snapshot which basically stores a snapshot of how data looked at a certain period of time. What I'm building is a method that loops through the snapshots for each events, and builds a small hash outlining the ownership over time for a given shareholder.
def fetch_ownership_over_time(shareholder, captable)
#shareholder = Shareholder.find(shareholder.id)
#captable = Captable.find(captable.id)
#company = #captable.company.id
#ownership_over_time = []
#captable.events.collect(&:snapshot).each do |snapshot|
parsed_snapshot = JSON.parse(snapshot)
#ownership_over_time.push(parsed_snapshot["event"]["name"])
#ownership_over_time.push(parsed_snapshot["event"]["date"])
parsed_snapshot["shareholders"].each do |shareholder|
if shareholder["id"] == #shareholder.id
#ownership_over_time.push(shareholder["ownership_percentage"])
end
end
end
return #ownership_over_time
end
I then call this method in my view which successfully retrieves the correct values however they are not structured in any way:
["Event 1 ", "2018-11-19", "0.666666666666667", "Event 2 ", "2018-11-19", "0.333333333333333", "4th event ", "2018-11-19", "0.315789473684211"]
What I'd like to do now though is construct my hash so that each separate snapshot event contains a name, date and ownership_percentage.
Perhaps something like this:
ownership_over_time = [
{
event_name = "Event 1" #parsed_snapshot["event"]["name"]
event_date = "20180202" #parsed_snapshot["event"]["date"]
ownership_percentage = 0.37 #shareholder["ownership_percentage"]
},
{
event_name = "Event 2" #parsed_snapshot["event"]["name"]
event_date = "20180501" #parsed_snapshot["event"]["date"]
ownership_percentage = 0.60 #shareholder["ownership_percentage"]
}
]
My challenge though is that the ["event"]["name"] an ["event"]["date"] attributes I need to fetch when looping over my snapshots i.e. the first loop (.each do |snapshot|) whereas I get my ownership_percentage when looping over shareholders - the second loop (.each do |shareholder|).
So my question is - how can I build this hash in "two" places so I can return the hash with the 3 attributes?
Appreciative of guidance/help - thank you!
You have to create a new hash for the object and append that hash to the array of objects you are creating.
def fetch_ownership_over_time(shareholder, captable)
#shareholder = Shareholder.find(shareholder.id)
#captable = Captable.find(captable.id)
#company = #captable.company.id
#ownership_over_time = []
#captable.events.collect(&:snapshot).each do |snapshot|
parsed_snapshot = JSON.parse(snapshot)
shareholder = parsed_snapshot['shareholders'].select { |s| s['id'] == #shareholder.id }.first
local_snapshot = {
'event_name' => parsed_snapshot['event']['name'],
'event_date' => parsed_snapshot['event']['date'],
'ownership_percentage' => shareholder.try(:[], "ownership_percentage") || 0
}
#ownership_over_time.push local_snapshot
end
return #ownership_over_time
end
Notice that I changed your second loop to a select. As you currently have it, you risk on pushing two percentages if the id is found twice.
EDIT:
Added functionality to use a default value if no shareholder is found.

doing away with loop result in rails

I am working on a kind of order where I have multiple amount in different currencies in just one attribute. So am trying to make sum on different currencies inside that attribute using other attributes in the table, which works fine but outputs the result as a count of all the rows instead of just showing the sum of the random values calculated.
orders_controller.rb
module Admin
module Statistic
class OrdersController < BaseController
def show
#orders_grid = ::Statistic::OrdersGrid.new(params[:statistic_orders_grid]) do |value|
value.page(params[:page]).per(20)
end
#assets = #orders_grid.assets
##fee_groups = {:fee => #assets.sum(:fee)}
#fee_groups = {
:fee => #assets.sum{|t|
olaoa = t.type
market_string = t.currency
base_currency = market_string.slice(0..2)
quote_currency = market_string.slice(3..5)
if olaoa == 'OrderBid' and base_currency == 'btc'
"#{ t.fee.to_s + ' ' + base_currency.upcase }"
elsif olaoa == 'OrderAsk' and quote_currency == 'ngn'
"#{ t.fee.to_s + ' ' + quote_currency.upcase }"
end
}
}
#orders_filter = true
#orders_group = true
end
end
end
end
summary.htm.slim
.panel.panel-default
.panel-heading
h4.panel-title.row
a data-parent="#filter-accordion" data-toggle="collapse" href="#summary"
span.col-xs-8.text-muted = t('admin.statistic.summary')
span.col-xs-4.text-right.text-muted = t('admin.statistic.click-to-expand')
#summary.panel-collapse.collapse
.panel-body
.datagrid-groups
- if !#orders_group
- if groups
- groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = val
- if #orders_group
/ Summary Count Loop
- if groups
- groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = pluralize(val, 'Order')
/ Summary Fees Loop. This is the Fee loop causing problem if am rigth and I dont know how to fix this.
- if #fee_groups
- #fee_groups.each do |key, val|
.datagrid.group.row
span.col-xs-2.title = t("admin.statistic.#{controller_name}.#{controller.action_name}.#{key}")
span.col-xs-10.value = val
The result of the code
So as you can see it renders 0.0BTC 5 times because the filter only has 5 orders. How do i deal with this. I want just the sum of all BTCs to show in the result instead of showing it 5 times.
Any help will be appreciated.
Because you sum strings in you're #fee_groups query that will results in putting strings next to each other instead of a total amount.
If you call it like this
#fee_groups = { fee: #assets.sum{|t| t.fee}}
You will get the total sum of you're assets.

Send 2 json from server to angularjs controller by 1 request

In a rails project, I have 1 controller and 2 model. I want send 1 request from angularjs to rails server and for response, get 2 json array, 1. first model. 2. seccond model.
Now I use below code, and get just 1 of 2 array:
Rails Contorller: tables_controller.rb:
class Api::V1::TablesController < Api::V1::BaseController
def index
#table = Table.all
#mostagheltype = Mostagheltype.all
//I can just send 1 of model.
respond_with(Table.all)
end
end
Angularjs Controller: table.js:
$scope.tables = Tables.index();
tableService.js:
'use strict';
var app = angular.module('tableService', ['ngResource']);
app.factory('Tables', function($resource) {
return $resource('/api/tables.json', {}, {
index: { method: 'GET', isArray: true}
});
});
I can push 2 table in 1 array in rails controller and then recieve this from angular controller, like below:
array = []
Table.all.each do |table|
array << { name: table.name, check: 1 }
end
Mostagheltype.all.each do |m|
array << { name: mostagheltype.name, check: 2}
end
//I can seprate 2 array by `check` value in angularjs part.
but I want a solution that I send each array separate. How can I do this? Any idea?
Short answer no. You can't have two responses to one request. You can respond with an object that contains both arrays.
My is a little rusty. So this may be more psuedo code than ruby;
obj = {}
obj.array1 =[]
obj.array2 =[]
Then populate each array and return the object.

How do I add an addPolylines feature to gmaps4rails?

I'm working with the gmaps4rails gem (version 1.5.6), and I want to add the ability to add more Polylines to a map rather than replacing the Polylines that are already there. On github, this code is viewable here.
This feature already exists for Markers:
Gmaps.map.replaceMarkers(your_markers_json_array); Gmaps.map.addMarkers(your_markers_json_array);.
The Markers feature seems to be laid out in two places:
1) In gmaps4rails.base.js as:
Gmaps4Rails.prototype.addMarkers = function(new_markers) {
this.markers = this.markers.concat(new_markers);
this.create_markers();
return this.adjustMapToBounds();
};
2) In gmaps4rails.base.js.coffee as:
#add new markers to on an existing map
addMarkers : (new_markers, adjustBounds = true) ->
#update the list of markers to take into account
#markers = #markers.concat(new_markers)
#put markers on the map
#create_markers()
#adjustMapToBounds() if adjustBounds
I figured I could work with the replacePolylines code in to make my own addPolylines call:
1) In gmaps4rails.base.js near the replacePolylines code as:
Gmaps4Rails.prototype.addPolylines = function(new_polylines) {
this.polylines = this.polylines.concat(new_polylines);
this.create_polylines();
return this.adjustMapToBounds();
};
2) In gmaps4rails.base.js.coffee near the replacePolylines code as:
#add new polylines to on an existing map
addPolylines : (new_polylines) ->
#update the list of polylines to take into account
#polylines = #polylines.concat(new_polylines)
#put polylines on the map
#create_polylines()
#.... and adjust map boundaries
#adjustMapToBounds()
I've made these changes to the gem that's already added to my Rails project, and I've restarted my Rails server. I call it the same way I call replacePolylines, with Gmaps.map.addPolylines(your_polylines_json_array);. It produces an error in the console: Uncaught TypeError: Object #<Gmaps4RailsGoogle> has no method 'addPolylines'.
There doesn't seem to be anywhere else in the gmaps4rails project where I have to do anything for my addPolylines call, but I'm obviously not doing something right. Can anyone explain what I need to do to get this to work, based on this information?
As a workaround, until I can figure out how to build the functionality into gmaps4rails itself, I've taken these measures to asynchronously load Polylines onto a map...
In my UsersController, I've set up the show action to build a blank #polylines_json set:
def show
#user = User.find(params[:id])
#polylines_json = {}
end
The idea here is to have nothing for gmaps4rails to display on its initial map load, so that the initial page display is as quick as possible. In the view, I'm loading the map with this line:
<%= gmaps( :polylines => { :data => #polylines_json }, :map_options => { :type => 'HYBRID', :zoom => 12, :auto_adjust => false, :center_latitude => "-77", :center_longitude => "21" } ) %>
Back in the UsersController, I've got a custom action maps that is set up to handle json requests that contain from and to parameters (so that I can find items within specific ranges). It's in this action that I'm building the actual Polyline json data based on the from/to parameters:
def items
items = items.find(:all, :conditions => ['id >= ? AND id <= ?', params[:from], params[:to]])
polyline = []
i=0
items.each do |item|
polyline[i] = []
polyline[i] += [{:lng=>item.longitude.to_f,:lat=>item.latitude.to_f}]
i += 1
end
#polylines_json = polyline.to_json
respond_to do |format|
format.json { render json: #polylines_json }
end
end
Finally, back in the view to bring it all together, I'm asynchronously building up the Polyline collection ten at a time until I retrieve them all from the database:
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
numberOfItems = <%= #user.items.count %>;
var polylines= [];
function LoadMap(from, to) {
if (to < numberOfItems){
nextFrom = to + 1;
nextTo = to + 10;
}
if(nextTo <= numberOfItems){
$.ajax({
dataType: 'json',
url: "http://<%= request.host %>/users/<%= #user.id %>/maps.json?from="+from+"&to="+to,
success: function(response) {
polylines = polylines.concat(response);
Gmaps.map.replacePolylines(polylines);
LoadMap(nextFrom, nextTo);
}
});
}
}
LoadMap(1,10);
</script>
<% end %>

Resources