Tracking wins & losses with PSQL/DataMapper - ruby

I have a User class which allows people to register and play a game; I also have a Game class, which contains the logic of said game (RPS).
When people register, their information is held in a psql database. The informations is obtained using params. It looks like this:
Class User
attr_reader :weapon
include DataMapper::Resource
property :id, Serial
property :name, String, required: true
property :email, String, required: true, unique: true
property :password_digest, Text
attr_reader :password
attr_accessor :password_confirmation
validates_confirmation_of :password
validates_format_of :email, as: :email_address
has n, :games
The corresponding Game class, contains this DB logic:
class Game
include DataMapper::Resource
property :id, Serial
property :win, ?
property :lose, ?
belongs_to :user
My issue is that I really don't know how to keep a record of how many games the user has won/lost. Do I need (or should I have separate classes for wins and losses? What key type should I use (serial/int)? All I want is for 'win' or 'lose' to increment by one each time the player...well, wins or loses.
All help/knowledge shared is greatly appreciated.
Thanks.

One way to do it could be to add two integer columsn "wins" and "losses" to User, and make helper methods to increment:
property :wins, Integer, default: 0
property :losses, Integer, default: 0
# usage: user.increment(:wins) or user.increment(:losses)
def increment(type)
update({ type => (send(:type) + 1) })
end

Related

Datamapper: count favs

I am working on a Sinatra image app. I have defined Datamapper models for my users, the uploaded images, and "Favs". Each user can give a maximum of one "Fav" to each image.
class User
include DataMapper::Resource
property :id, Serial
property :privilege_lvl, Integer, :default => 0
property :name, String, :unique => true
property :password_hash, BCryptHash
has n, :images
has n, :comments
has n, :favs
end
class Image
include DataMapper::Resource
property :id, Serial
mount_uploader :file, ImageUploader
belongs_to :user
property :posted_at, DateTime
has n, :comments
has n, :favs
end
class Fav
include DataMapper::Resource
property :id, Serial
belongs_to :image
belongs_to :user
end
Is there a way to count the total number of Favs a user has received without iterating over all the images of the user and summing up the Favs of each image?
Sounds like you need a counter cache:
This could be as simple as adding a :favs_cache to users and incrementing it whenever favs are added.
You might also want to check out this gem: dm-counter-cache

One-to-one DataMapper association

I'm very new to DataMapper, and I'm trying to create models for the following scenario:
I've got a number of users (with a user name, password etc.), who can also be players or referees or both (so Single Table Inheritance is not an option). The base models would be:
class User
include DataMapper::Resource
property :id, Serial
# Other user properties go here
end
class Player
include DataMapper::Resource
property :id, Serial
# Other player properties go here
# Some kind of association goes here
end
class Referee
include DataMapper::Resource
property :id, Serial
# Other referee properties go here
# Some kind of association goes here
end
DataMapper.finalize
I'm not sure, though, what kinds of associations to add to Player and Referee. With belongs_to :user, multiple players can be associated with the same user, which doesn't make sense in my context. In RDBMS terms I guess what I want is a unique constraint on the foreign key in the Players and Referees tables.
How do I accomplish this in my DataMapper model? Do I have to perform the check myself in a validation?
There are different ways you could do this. Here's one option:
class User
include DataMapper::Resource
property :id, Serial
# Other properties...
has 1, :referee, :required => false
has 1, :player, :required => false
end
class Referee
include DataMapper::Resource
# DON'T include "property :id, Serial" here
# Other properties...
belongs_to :user, :key => true
end
class Player
include DataMapper::Resource
# DON'T include "property :id, Serial" here
# Other properties...
belongs_to :user, :key => true
end
Act on the referee/player models like:
u = User.create(...)
u.referee = Referee.create(...)
u.player = Player.create(...)
u.player.kick_ball() # or whatever you want to call
u.player.homeruns
u.referee.flag_play() # or whatever.
See if this works. I haven't actually tested it but it should be good.
The previous answer works other than :required => false is not recognized for has 1 properties.
It's also confusing because for has n properties, you can use new right on the property or otherwise treat it as a collection. In your example, you would be tempted to code
u = User.create ...
u.referee.create ...
But that fails in the case of has 1 because the property is a single value, which begins life as nil and so you have to use the method the previous answer indicates. Also, having to explicitly make the belongs_to association into the key is a little confusing.
It does seem to execute validations and have the right association actions (so u.save will also save the referred-to Referee). I just wish it were more consistent between has n and has 1.

Datamapper: How to count total score from has_many objects

I just started learning some database basics. I am using Ruby and the datamapper gem
I have two simple objects:
class Quote
include DataMapper::Resource
property :id, Serial
property :saying, String, :required => true
property :score, Integer, :default => 5
belongs_to :user
end
and
class User
include DataMapper::Resource
property :id, Serial
has n, :quotes
end
No I would like to get the total score of a user. The total score is the sum of the scores of all associated quotes of a user.
I tried something like
#totalscore = #user.quotes.inject(0) {|count, q| count + q.score}
but I guess this can't be the way I am supposed to use a database, right?
Any help is appreciated!
Best,
Tobi
I am not running the code, but by looking at the docs, I think something like this should work:
#totalscore = #user.quotes.sum :score

Correct way to make a DataMapper association

I want to have a table of users. These users shall have n contacts and n messages..
My code is:
...
class User
include DataMapper::Resource
property :id, Serial, :key => true
property :nickname, String
has n, :contacts
has n, :messages
end
class Contact
include DataMapper::Resource
belongs_to :user
property :id, Serial, :key => true
property :authgiven, String
has 1, :user
end
class Message
include DataMapper::Resource
belongs_to :user
property :id, Serial, :key => true
property :data, String
end
#apply models (validation etc.)
DataMapper.finalize
...
There are no errors initializing DataMapper, but when I try to create a new User or whatever, save always returns false... Can someone please point out what is wrong?
I'm quite new to DataMapper, it always worked for me with simple tables without relationships, so I believe it has to do with the way I declared the 1:n relationship...
Hey you should remove that has 1, :user line from Contact model and you should be good.

DataMapper has n with conditions

By any chance is it possible to create a conditional association with DataMapper?
For example:
I want the User have n Apps just if that user have the attribute :developer => true
something like this:
class User
include DataMapper::Resource
property :id, Serial
property :name, String, :nullable => false
property :screen_name, String, :nullable => false, :unique => true
property :email, String, :nullable => false, :unique => true, :format => :email_address
property :password, BCryptHash, :nullable => false
property :developer, Boolean, :default => false
#The user just gets apps if developer
has n :apps #,:conditions => "developer = 't'"
end
class App
include DataMapper::Resource
property :id, Serial
property :name, String, :nullable => false
belongs_to :user
end
I know that this would be possible by creating a subclass from User as a Developer::User and in that class, use the has n, but I really would like to know if its possible to make it directly on the association declaration.
Another way I also managed to do when using ARn was to extend the association and rewriting the methods for each action.
So on the extension module I could have something like this:
module PreventDeveloperActions
def new
if proxy_owner.developer?
super
else
raise NoMethodError, "Only Developers can create new applications"
end
end
# and so on for all the actions ...
end
But again, I really would like to avoid the use of this solutions if possible, but just if it's possible to perform a quick and direct method easily with DataMapper :)
Thanks in advance
At the moment, conditions that you include in the relationship declaration only apply to the target. So if the target model has an :active property, you can say things like has n, :apps, :active => true. Unfortunately you can't define relationships that are only active given the current state of the source (yet).
There are some proposals I'm considering to expand the Query logic in DM, but I'm unsure what the impact will be to the code, and what extra capabilities it will provide aside from this. It may be something we tackle after DM 1.0, since it also affects 50+ adapters and plugins.
STI is normally what I'd recommend for something like this, since it will allow you to define relationships that only exist for that type of object. Another approach would be to define the relationships as normal, mark the accessor/mutator methods as private, and then add a proxy method that does the equivalent of return apps if developer?.

Resources