Redis in rails, backbone - ruby-on-rails

Im learning Redis and trying it to run with rails and backbone. I need to GET/SET 50 values every 66ms on my front-end. I need to have objects (#monsters) with redis and i did them this way. I dont really know or its becouse my computer slow or code weak, or backbone's beginners code is slowing my calculations, but after 3 seconds all PUT/GET to database pending and everything working slower and slower. I'm debugging with localhost, maybe when i push to heroku it is fast enough to update all data becouse of heroku servers? or not? How could i improve the dataSET/dataGET?
My random Redis key and value in console looks like:
2.1.2 :002 > $redis.get('1001')
=> "[452,305,452,316,3]"
# (X position, Y position, Targets X position, Targets Y position, Level)
i have 50 keys named from '1001' to 1050' with values of each monster Xpos, Ypos, XposDest, YposDest positions which gonna be on canvas map. These are parsed to objects with Rails and fetched to backbone.
# Getting all values from Redis database and sending to backbone.
class MainController < ApplicationController
def index
m = []
for key in $redis.keys do
value = JSON.parse($redis.get(key))
m.push id: key.to_i,
Xpos: value[0],
Ypos: value[1],
XposDest: value[2],
YposDest: value[3],
level: value[4]
end
#monsters = m
end
# Getting all values from Backbone and updating Redis database.
class MonstersController < ApplicationController
def update
id = monster_params[:id]
xpos = monster_params[:Xpos]
ypos = monster_params[:Ypos]
xposDest = monster_params[:XposDest]
yposDest = monster_params[:YposDest]
level = monster_params[:level]
$redis.set id, [xpos,ypos,xposDest,yposDest,level].to_json
respond_to do |format|
format.html do
render nothing: true
end
end
end
private
def monster_params
params.require(:monster)
end
end
here goes my backbone important part
Sprint.Views.Maps ||= {}
class Sprint.Views.Maps.IndexView extends Backbone.View
initialize: ->
if move_on_count is 0
#addAll()
#game_init_function()
mob_x_post = []
mob_y_post = []
mob_x_posdest = []
mob_y_posdest = []
move_on_count = 0
game_init_function: ->
#receiving_attributes_from_database()
#move_on()
move_on: ->
move_on_count++
self = this
timer 66, ()-> self.fetch_mobs_from_redis_db()
fetch_mobs_from_redis_db: ->
self = this
#addAll
#save_mobs_position()
#receiving_attributes_from_database()
addAll: () =>
#options.monsters.each(#addOne)
addOne: (monster) =>
monstersas.push monster
mobbys.push monster.attributes.level
save_mobs_position: ->
for alfa in [0..(monstersas.length-1)]
#options.monsters.models[alfa].save((level: alfa+1, YposDest: parseInt(mob_y_posdest[alfa]), XposDest: parseInt(mob_x_posdest[alfa]), Ypos: parseInt(mob_y_post[alfa]), Xpos: parseInt(mob_x_post[alfa])))
receiving_attributes_from_database: ->
for cnt in [0..(monstersas.length-1)]
mob_y_post[cnt] = monstersas[cnt].attributes.Ypos
mob_x_post[cnt] = monstersas[cnt].attributes.Xpos
mob_y_posdest[cnt] = monstersas[cnt].attributes.YposDest
mob_x_posdest[cnt] = monstersas[cnt].attributes.XposDest
# here goes big canvas code..
Im still learning rails, backbone, coffeescript, redis.. Here i believe are so many things that could make my game running slow..

Related

Editing multidimensional table with uncertain dimensions in Lua

I want to be able to access and edit values in a user-generated table, that can have any number of dimensions.
Say, for this nested table,
table = {
'1',
{
'2.1',
'2.2'
},
{
{
'3.1.1',
'3.1.2'
},
'3.2'
},
}
I would have another table that contains a location for the needed data,
loc = {3, 1, 2}
Ideally, what I'd want is to be able to not only access but edit the values in the table, similar to using table[3][1][2] but by utilizing the loc table,
print(table[loc[1]][loc[2]][loc[3]]) --returns 3.1.2
print(table[loc]) --hypothetically something like this that takes each indexed member of the table in order
I also want to be able to edit this table.
table[loc] = {'3.1.2.1', '3.1.2.2'}
I need to be able to edit the global table, so cannot use the methods listed in this reddit thread, and haven't been able to find the right way to use metatables for this yet. I appreciate the help, thanks.
I think you could simply write an additional function for this purpose.
function TreeGetValue (Tree, Location)
local CorrectTree = true
local Index = 1
local Dimensions = #Location
local SubTable = Tree
local Value
-- Find the most deep table according to location
while (CorrectTree and (Index < Dimensions)) do
local IndexedValue = SubTable[Location[Index]]
if (type(IndexedValue) == "table") then
SubTable = IndexedValue
Index = Index + 1
else
CorrectTree = false
end
end
-- Get the last value, regarless of the type
if CorrectTree then
Value = SubTable[Location[Index]]
end
return Value
end
Here, we assume that the tree is well-formatted as the beginning. If we find any problem we set the flag CorrectTree to false in order to stop immediately.
We need to make sure we have a table at every dimension in order index a value from.
> TreeGetValue(table, loc)
3.1.2
Obviously, it's also easy to to write the set function:
function TreeSetValue (Tree, Location, NewValue)
local Index = 1
local Dimensions = #Location
local SubTable = Tree
-- Find the most deep table according to location
while (Index < Dimensions) do
local IndexedValue = SubTable[Location[Index]]
-- Create a new sub-table if necessary
if (IndexedValue == nil) then
IndexedValue = {}
SubTable[Location[Index]] = IndexedValue
end
SubTable = IndexedValue
Index = Index + 1
end
-- Set or replace the previous value
SubTable[Location[Index]] = NewValue
end
And then to test it with your test data:
> TreeGetValue(table, loc)
3.1.2
> TreeSetValue(table, loc, "NEW-VALUE")
> TreeGetValue(table, loc)
NEW-VALUE

Is there a way I can use a rake task or method that can rewrite an HTML partial using erb?

Sorry for the confusing title, but I will elaborate here.
ok so on the users index page of my site I have a list of Top Trending songs. The list is ordered by user rankings and this list changes dynamically as each songs aggregate ranking changes relative to each other.
class SongratingsController < ApplicationController
#Top100 = Rails.cache.read('Top100')
lastSpot = #Top100.last
def reCalcTop100
#Top100 = Song.where('num_stars > ?', 0 ).order('num_stars desc, total_score desc').limit(100)
Rails.cache.fetch('Top100'){#Top100}
end
def addRatingToSong
userID = params[:uid].to_i
songId = params[:sid].to_i
rVal = params[:valR].to_i
#averageS = []
songRate = Songrating.find_by(:user_id => userID, :song_id => songId)
if songRate != nil
oldScore = songRate.rating
songRate.update_attributes(:rating => rVal)
#song = Song.find(songId)
score = #song.total_score - oldScore
newScore = score + rVal
averageScore = newScore/#song.songratings_count
#song.update_attributes(:total_score => newScore,:num_stars => averageScore)
#averageS[0] = averageScore
#averageS[1] = #song.songratings_count
else
Songrating.create!(:user_id => userID, :song_id => songId,:rating => rVal)
#song = Song.find(songId)
newScore = #song.total_score + rVal
averageScore = newScore/#song.songratings_count
#song.update_attributes(:total_score => newScore,:num_stars => averageScore)
#averageS[0] = averageScore
#averageS[1] = #song.songratings_count
end
if newScore > lastSpot.total_score && averageScore > lastSpot.num_stars
reCalcTop100
end
if request.xhr?
render :json => {
:starData => #averageS
}
end
end
end
As you can see in these two photos below I have a view partial that shows this list, but right now I have the list generated each time a user logs into the main page. But since this list is not unique to the user, I feel I am wasting time regenerating this list.
ideally I would like to generate and write a static HTML partial only when the top100 list changes, but I don't really know how to accomplish this.
thanks.
Yep just use erb
vars = OpenStruct.new({some_var: some_val})
rendered_html = ERB.new(File.read("#{Rails.root}/app/templates/embed_code.html.erb")).result(vars.instance_eval { binding })
This will put the rendered html in the rendered_html variable from there you can write it to a file or do anything you want. This should work in the context of a ruby class or rake task afaik.
The vars are passed to the template and can be used as <%= some_var %> in the template.
Now that i've answered you actual question, i think the better solution is to just use Rails.cache to cache the rendered data.
Anything that takes a long time can be cached with
result = Rails.cache.fetch "some_cache_key" do
# things you want to cache
end
this will cache the block and return it to result. if unstale cached data exisits in the future it will just return it from cache, if cache is empty or stale it will re-execute the block and return it into result.
Finally in the context fo a controller you can just use action caching which is a bit more hands off.
See: http://guides.rubyonrails.org/caching_with_rails.html for more details.

Relationships - accessing children elements

I'm trying to add a simple inventory management system. A class product has_many variants, and the variants belong_to a product and therefore have a product_id, along with a name and a quantity. When the user creates the product, I have the product generate 11 different variants (just with numerical values) by calling the following
Located in variants.rb (model)
def self.create_multiple_variants( product_id )
p = Product.find(product_id)
i = 11
while i <= 21
new_variant = Variants.create
new_variant.product = p
new_variant.name = (i*2)
new_variant.qty = 0
i += 1
end
end
Then when the user tries to show the page, the program will go through each variant belonging to the product and see if their is any quantity (which the admin adjusts along the way) like so:
Located in the view:
<div class="size"><br/>Size: <%= f.select(:size, #sizes_availiable, :prompt => "Select a Size...")
Located in product_controller:
#sizes_availiable = Variants.create_inventory_array( #product.id )
Located in variants.rb (model)
def self.create_inventory_array( product_id )
p = Product.find(product_id)
a = []
p.variants.each do |v|
a << variant.name if variant.qty > 0
end
a
end
I know with the naming it is a little confusing, as I am setting it up as something bigger but deprecating it for now, so sorry of thats a little confusing. For now you can think of variant as "size"
But the creation portion of it works fine, however when I go to show the product I get this message:
NameError in ProductController#show
app/models/variants.rb:20:in create_inventory_array'
app/controllers/product_controller.rb:18:inshow'
I assume that the way I am building the relationship is the source of the problem, either that or how I am calling it. Any ideas?
UPDATE:
I used the suggestions below, and it seems that now the problem lies in the second function. Here is my new variants.rb and the error I get:
class Variants < ActiveRecord::Base
attr_accessible :product_id, :name, :qty
belongs_to :product
def self.create_multiple_variants( product_id )
p = Product.find(product_id)
for i in 11..21
v = Variants.create
v.product = p
v.name = (i*2)
v.qty = 0
v.save!
end
end
def self.create_inventory_array( product_id )
p = Product.find(product_id)
a = []
p.variants.each do |variant|
a << variant.name if variant.qty > 0
end
a
end
end
NoMethodError in ProductController#create
undefined method `Variants' for #<Product:0x007fe9561ad550>
Application Trace | Framework Trace | Full Trace
app/models/variants.rb:8:in `block in create_multiple_variants'
app/models/variants.rb:7:in `each' app/models/variants.rb:7:in
`create_multiple_variants' app/controllers/product_controller.rb:33:in
`create
I still believe it's an issue with how the relationship is being build (I'm assigning variants.product = current_product, yet I call product.variants - I feel like the relationship is not being built both ways)
The problem is in this code:
p.variants.each do |v|
a << variant.name if variant.qty > 0
end
you pass in the variable v but refer to it as variant. To fix it change the line to
p.variants.each do |variant|
Also read this: http://guides.rubyonrails.org/active_record_querying.html#conditions you could make the code a lot more elegant by querying the variants for desired product_id and qty, and then calling map to get the names only.
Also this can be improved:
new_variant = Variants.create
new_variant.product = p
new_variant.name = (i*2)
new_variant.qty = 0
to
new_variant = p.variants.create name: "#{i*2}", qty: 0
Yes. You need to save the object.
To save it at the end of your loop:
new_variant.save!
Sidenote about this loop:
i = 11
while i <= 21
...
i += 1
end
This is a better way to write it because it's clearer:
for i in 11..21 do
...
end
And for blocks like this:
new_variant = Variants.create
new_variant.product = p
new_variant.name = (i*2)
new_variant.qty = 0
new_variant.save!
Make it easier to read:
v = Variants.create
v.product = p
v.name = i*2
v.qty = 0
v.save!
I figured out what was wrong - my model is Variants.rb (with an s) which at some point caused a problem. I renamed the file variants.rb as well as the class name Variants to variant.rb and Variant respectivly, restarted the server, and it worked! Thanks to those who helped!

Nested ActiveRecords: Find many childrens of many parents

In my Rails 3.2 app a Connector has_many Incidents.
To get all incidents of a certain connector I can do this:
(In console)
c = Connector.find(1) # c.class is Connector(id: integer, name: string, ...
i = c.incidents.all # all good, lists incidents of c
But how can I get all incidents of many connectors?
c = Connector.find(1,2) # works fine, but c.class is Array
i = c.incidents.all #=> NoMethodError: undefined method `incidents' for #<Array:0x4cc15e0>
Should be easy! But I don't get it!
Here’s the complete code in my statistics_controller.rb
class StatisticsController < ApplicationController
def index
#connectors = Connector.scoped
if params['connector_tokens']
logger.debug "Following tokens are given: #{params['connector_tokens']}"
#connectors = #connectors.find_all_by_name(params[:connector_tokens].split(','))
end
#start_at = params[:start_at] || 4.weeks.ago.beginning_of_week
#end_at = params[:end_at] || Time.now
##time_line_data = Incident.time_line_data( #start_at, #end_at, 10) #=> That works, but doesn’t limit the result to given connectors
#time_line_data = #connectors.incidents.time_line_data( #start_at, #end_at, 10) #=> undefined method `incidents' for #<ActiveRecord::Relation:0x3f643c8>
respond_to do |format|
format.html # index.html.haml
end
end
end
Edit with reference to first 3 answers below:
Great! With code below I get an array with all incidents of given connectors.
c = Connector.find(1,2)
i = c.map(&:incidents.all).flatten
But idealy I'd like to get an Active Records object instead of the array, because I'd like to call where() on it as you can see in methode time_line_data below.
I could reach my goal with the array, but I would need to change the whole strategy...
This is my time_line_data() in Incidents Model models/incidents.rb
def self.time_line_data(start_at = 8.weeks.ago, end_at = Time.now, lim = 10)
total = {}
rickshaw = []
arr = []
inc = where(created_at: start_at.to_time.beginning_of_day..end_at.to_time.end_of_day)
# create a hash, number of incidents per day, with day as key
inc.each do |i|
if total[i.created_at.to_date].to_i > 0
total[i.created_at.to_date] += 1
else
total[i.created_at.to_date] = 1
end
end
# create a hash with all days in given timeframe, number of incidents per day, date as key and 0 as value if no incident is in database for this day
(start_at.to_date..end_at.to_date).each do |date|
js_timestamp = date.to_time.to_i
if total[date].to_i > 0
arr.push([js_timestamp, total[date]])
rickshaw.push({x: js_timestamp, y: total[date]})
else
arr.push([js_timestamp, 0])
rickshaw.push({x: js_timestamp, y: 0})
end
end
{ :start_at => start_at,
:end_at => end_at,
:series => rickshaw #arr
}
end
As you only seem to be interested in the time line data you can further expand the map examples given before e.g.:
#time_line_data = #connectors.map do |connector|
connector.incidents.map do |incident|
incident.time_line_data(#start_at, #end_at, 10)
end
end
This will map/collect all the return values of the time_line_data method call on all the incidents in the collection of connectors.
Ref:- map
c = Connector.find(1,2)
i = c.map(&:incidents.all).flatten

ruby array serialization not working

I have the following code in my model:
def getFormattedAverages
averages = Array.new();
self.items.each do |i|
x = self.responses.average(:x,:conditions=>['item_id = ?',i.id])
if x.nil?
x = 2000
else
x = x.to_i
end
y = self.responses.average(:y,:conditions=>['item_id = ?',i.id]).to_i
if y.nil?
y = "*"
end
averages.push([[x,y]])
end
return averages
end
In the view I have:
var dataseries = <%=#question.getFormattedAverages%>;
On my development machine, I get the data in exactly the form I need to pass into my graphing function. It looks like this when I "view source" on the rendered page:
var dataseries = [[[31, 34]], [[45, 33]], [[34, 23]], [[10, 27]], [[21, 37]]];
But when I run it on my production server, it looks like this-
var dataseries = -6745-798571322000010791-2270-18;
Note that the x and y data on my development and production servers is different. The point is that all of the brackets and commas are being stripped out. Any help you can provide would be much appreciated - this one really has me stumped!
I found this answer.
Changing the code in my view to read
var dataseries = <%=raw #question.getFormattedAverages.to_json%>;
seems to work!

Resources