I am making a sports leaderboard in rails and trying to mass assign a column with values calculated from other columns. Following is the names of the columns: :pts
, :games_played
, and :pts_per_game
. The first two already have values assigned and I want to insert value into the last one by dividing :pts by :games_played. So I went to rails console and tried
PlayerLeaderboard.update_all(pts_per_game: pts/games_played)
But I get this output with NoMethodError
NoMethodError: undefined method `pts' for main:Object
from (irb):24
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `block in require'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
from /Users/AYL/Dropbox/workspace/rails/krossover/bin/rails:8:in `<top (required)>'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/commands/rails.rb:6:in `call'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/command_wrapper.rb:38:in `call'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:183:in `block in serve'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:156:in `fork'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:156:in `serve'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:131:in `block in run'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:125:in `loop'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application.rb:125:in `run'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/gems/2.1.0/gems/spring-1.3.6/lib/spring/application/boot.rb:18:in `<top (required)>'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from /Users/AYL/.rvm/rubies/ruby-2.1.5/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from -e:1:in `<main>'irb(main):025:0>
The weird thing is I tried this approach before and it worked. I just switched my development db from sqlite3 to postgres and re-seeded data. It seems very unlikely to me that switching db is the reason for this error; I must have missed something.
I also tried update_column
.
Thanks in advance!
That code is treating pts
and games_played
as local variables or methods on self
. There are no such methods, hence the error.
You want columns so you need to send a bit of SQL into update_all
instead of a Ruby hash:
PlayerLeaderboard.update_all('pts_per_game = pts / games_played')
Presumably pts
and games_played
are integer columns so you're going to have truncation problems here. If that's what you want (i.e. 5 / 3
being 1
) then there's nothing to worry about. If your pts_per_game
is floating point, then you'll need to throw a cast in the mix:
PlayerLeaderboard.update_all('pts_per_game = cast(pts as float) / games_played')
PlayerLeaderboard.update_all('pts_per_game = pts::float / games_played')
The cast
is standard SQL, the ::
syntax is PostgreSQL-specific.
If your pts_per_game
is an integer and you want it rounded, then you'll have to say so:
PlayerLeaderboard.update_all('pts_per_game = round(cast(pts as float) / games_played)')
If negative values are possible then you'll need to use ceil
or floor
instead of round
to choose which direction your negative values should be rounded.
If you have zeros in games_played
then you'll need to do two updates and decide what pts_per_game
should be when there haven't been any games, zero and NULL would be reasonable choices I suppose:
PlayerLeaderboard.where(:games_played => 0).update_all(...)
PlayerLeaderboard.where.not(:games_played => 0).update_all(:pts_per_game => 0)
If you're going with NULL for pts_per_game
when there aren't any games then you only need the first update_all
since new columns are NULL by default.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments