Please help me understand how arrays are translated in rails

I’ve spent hours researching the subject and have tried many test
sequences in IRB, and rails console but I’m just having trouble making
headway into what is probably a very easy subject.

I understand arrays with at least 4 other languages but with Ruby I
haven’t found a mental connection with how I can assign variables to
arrays…

Take for example:

def calculate_tsos(model, datavar, teamvar, valvar)
var = model.compiled_this_week.find(:all)
var.each_with_index do |rows, i|
puts “#{model} [ Row #{i} | Team ID = #{rows.team_id} | Team =
#{rows.team.name} | #{datavar} = #{rows.send(datavar)}”
end
end

This will give me:

TotalOffense [ Row 0 | Team ID = 5 | Team = Tulsa | ydspgm = 569.86
TotalOffense [ Row 1 | Team ID = 47 | Team = Houston | ydspgm = 562.77
TotalOffense [ Row 2 | Team ID = 20 | Team = Oklahoma | ydspgm = 547.86
etc. etc.

So far, so good. I can at least see the data that I want.

Now, I want to assign the Team ID and the ydspgm to variables that I can
manipulate and use later on. Normally, I would think that I could do
something like this:

def calculate_tsos(model, datavar, teamvar, valvar)
var = model.compiled_this_week.find(:all)
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamid[i]} | Team =
#{rows.team.name} | #{datavar} = #{teamval[i]}”
end
end

But I get a…

undefined method `[]=’ for 0:Fixnum

So, before responding let me explain what I’ve been trying to do and
perhaps you can explain to me how I “should” be doing it rather than the
way I have been trying to do it:

Summary: Rake task is being used to pull data, calculate data, and save
data.

In my rake file I am performing the following:

update_tsos_offense = TsosOffense.new
update_tsos_offense.calculate_tsos(TotalOffense, “ydspgm”, to_team_id,
to_value)

This creates a new object in TsosOffense. The method it’s calling is
the one I posted above that I’m having some difficulties with. I’m
supplying the model name, the field, a variable to store the team_id in,
and a value to store the field information in.

I was going to call a ruby file in libs from TsosOffense to perform my
calculations but perhaps I could just do the calculations in this
method.

Once I do my calculations for this portion of the rake task, it needs to
be “held in queue” - not saved, just waiting to be saved…

There are 13 more iterations in the rake task calling 13 other models
and 13 other fields, further assigning variables.

When all 14 of these calls are finished, I want to save all 14 columns
of information to my new table which is the table in the TsosOffense
model…

However, I’m having great difficulty in trying to find a best practices
scenario for doing this. I learn more from code and by doing than I do
anything. Could someone please provide a short idea of how I could
accomplish this?

Thank you kindly.

Okay, so I figured out what I was doing wrong.

This method:

def calculate_tsos(model, datavar, teamvar, valvar)
var = model.compiled_this_week.find(:all)
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamvar[i]} | Team =
#{rows.team.name} | #{datavar} = #{valvar[i]}”
end
end

… works fine …

The problem was I forgot to pass empty arrays with the method variables
in my rake file:

to_team_id = []
to_value = []
update_tsos_offense = TsosOffense.new
update_tsos_offense.calculate_tsos(TotalOffense, “ydspgm”, to_team_id,
to_value)

However, even doing this, I would like some feedback.

Should I be doing it this way or is there an easier way with what I’m
trying to accomplish?

Many thanks in advance.

On Jul 16, 2009, at 1:25 PM, Älphä Blüë wrote:

TotalOffense [ Row 0 | Team ID = 5 | Team = Tulsa | ydspgm = 569.86
something like this:

But I get a…

undefined method `[]=’ for 0:Fixnum

Down below you say you make this call and pass ‘to_team_id’ as the
argument to ‘teamvar’. So teamvar is an integer… not array. Just
above you are trying to do “teamvar[i]”. You can’t do that on an
integer (which is what your error is trying to tell you).

If it were me I’d do this:

def calculate_tsos(model, datavar)
var = model.compiled_this_week.find(:all)
teamvar = [] # you need this so that the variable continues to exist
after the each_with_index block.
valvar = [] # same for this one.
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamid[i]} | Team =
#{rows.team.name} | #{datavar} = #{teamval[i]}”
end
[teamvar, valvar] #return the results
end

And then call it like this:

tv, vv = calculate_tsos(…)

On Thu, 2009-07-16 at 22:25 +0200, Älphä Blüë wrote:

This will give me:
something like this:

But I get a…

undefined method `[]=’ for 0:Fixnum

I don’t understand the ‘0’ portion of the error message but the
problem’s not that you don’t understand arrays. Try naming your arrays
something else, leaving your method parameters as is. That should get
you going down a productive path.

HTH,
Bill

bill walton wrote:

On Thu, 2009-07-16 at 22:25 +0200, Älphä Blüë wrote:

This will give me:
something like this:

But I get a…

undefined method `[]=’ for 0:Fixnum

I don’t understand the ‘0’ portion of the error message but the
problem’s not that you don’t understand arrays. Try naming your arrays
something else, leaving your method parameters as is. That should get
you going down a productive path.

HTH,
Bill

Hi Bill, the issue was that the variables being passed to the class
method from rake were assigned to var=0 so that’s why I was getting that
error. I had forgotten to check my rake file and once I went back and
retraced my steps I realized I hadn’t passed the type of variable to the
class method (array in this case).

Further,

I have the method working like this now:

def calculate_tsos(model, datavar, teamvar, valvar)
var = model.compiled_this_week.find(:all, :order => :team_id)
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamvar[i]} | Team =
#{rows.team.name} | #{datavar} = #{valvar[i]}”
end
end

As a rake file test, I tried:

to_team_id = []
to_value = []
update_tsos_offense = TsosOffense.new
update_tsos_offense.calculate_tsos(TotalOffense, “ydspgm”, to_team_id,
to_value)
puts “From Rake to_team_id = #{to_team_id[1]} and to_value =
#{to_value[1]}”

And receive:

From Rake to_team_id = 2 and to_value = 484.85

… which is correct so it looks like the values were assigned to the
arrays and that I should be able to use them, once I finish manipulating
them (performing calculations).

But, again, is there a better way to do this? Should I not perform
calculations within the class method on that model? Or, should I keep
things neat and tidy by performing calculations in a ruby file within my
libs directory?

I just want to get better at what I’m doing…

Hi –

On Thu, 16 Jul 2009, Älphä Blüë wrote:

puts "#{model} [ Row #{i} | Team ID = #{teamvar[i]} | Team =
to_value = []
update_tsos_offense = TsosOffense.new
update_tsos_offense.calculate_tsos(TotalOffense, “ydspgm”, to_team_id,
to_value)

However, even doing this, I would like some feedback.

Should I be doing it this way or is there an easier way with what I’m
trying to accomplish?

In general, I would tend to have the method return values that you can
then assign to local variables, rather than creating accumulator
objects and passing them in as arguments.

update_tsos_offense = TsosOffense.new
to_team_id, to_value = calculate_tsos(TotalOffense, “ydspgm”)

and have the method return arrays:

def calculate_tsos(model, datavar)
teamvar, valvar = [], []
var = model.compiled_this_week.find(:all)
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamvar[i]} | Team =
#{rows.team.name} | #{datavar} = #{valvar[i]}”
end
return teamvar, valvar
end

I haven’t really gotten my head into the problem-space of the
application itself, so I’m being kind of mechanistic about moving code
around (and haven’t tested it), but that’s at least a broad-stroke way
of rethinking it.

(Another thing to think about would be whether the calculation method
might belong in a class, rather than as a top-level routine. But I
can’t really determine that from these excerpts.)

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (The Well-Grounded Rubyist)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)

On Thu, 2009-07-16 at 22:53 +0200, Älphä Blüë wrote:

Hi Bill, the issue was that the variables being passed to the class
method from rake were assigned to var=0 so that’s why I was getting that
error. I had forgotten to check my rake file and once I went back and
retraced my steps I realized I hadn’t passed the type of variable to the
class method (array in this case).

Yes. As Phillip pointed out, “teamvar is an integer… not array.”
Sorry I didn’t have time, and still don’t, to be more help. Reckoned
you’d figure it out with just a hint. At any rate, David has offered
advice and my recommendation is to listen carefully. You can’t do
better. When he says “I would tend…” he’s saying in the nicest way
possible “that’s not how we do it in Ruby.” Other than getters in
models, you won’t find many examples of ‘outbound’ parameters in Ruby
methods.

Best regards,
Bill

P.S. When he says “Another thing to think about…”, it often means he
already is thinking about it and if prompted with a question like ‘how
would that work?’ very often says more.

Thanks for the feedback David.

def calculate_tsos(model, datavar)
teamvar, valvar = [], []
var = model.compiled_this_week.find(:all, :order => :team_id)
var.each_with_index do |rows, i|
teamvar[i] = rows.team.id
valvar[i] = rows.send(datavar)
puts “#{model} [ Row #{i} | Team ID = #{teamvar[i]} | Team =
#{rows.team.name} | #{datavar} = #{valvar[i]}”
end
return teamvar, valvar
end

I used the same ordering process so my rows are uniform across the 14
inner rake tasks…

I had to change a bit of your code for the rake task:

update_tsos_offense = TsosOffense.new
to_team_id, to_value = update_tsos_offense.calculate_tsos(TotalOffense,
“ydspgm”)
puts “From Rake to_team_id = #{to_team_id[0]} and to_value =
#{to_value[0]}”

But it’s actually shorter and in a lot of ways cleaner and easier to
read. Plus, it’s two less variables I need to send with rake.

As to your other question,

I will be doing the following:

On each row within the each loop:

Finding the sum of all rows returned
Finding the mean of all rows returned
Finding the standard deviation between each value on the rows returned
Applying a ratings point modifier to the end value
… then returning the arrays with the new modified values…

Heya Rob,

I always try very hard to work on problems myself before asking
questions. I probably should have used pastie or gist to show my code a
little bit better:

http://pastie.org/548692

Here is the three phases of code that I’m going to be working with…

Rake file starts the task…
Model pulls data, stores it in variables, sends it to Tsos Class in libs
Tsos class calculates all data and returns the end results…
Variables are stored and queued…

Rake file starts the next subtask…

Variables are stored and queued…


etc…

After 14 subtasks are finished all variables are saved to the Model
table…

That’s what I would like to do…

On Jul 16, 2009, at 5:21 PM, bill walton wrote:

P.S. When he says “Another thing to think about…”, it often means
he
already is thinking about it and if prompted with a question like
‘how
would that work?’ very often says more.

Or a question that demonstrates that you HAVE thought about it. In
general, questions should always be asked after first stating what you
know (often with evidence like code or irb output).

-Rob

Rob B. http://agileconsultingllc.com
[email protected]