Structure for recurring unlimited voting contests - ruby-on-rails

I am in the planning stages of building an app where all users (registered or not) can vote every minute or so. The voting window should last a set period of time (for ex. 1 month). At which point a winning entity is defined and the voting period resets and starts all over. Visitors can then leave comments about the winner for that period. My question is what do you think is the best way to set something like this up?
Here are my current thoughts, but doesn't seem ideal:
1) Vote model: entity_id, contest_id, user_id (optional), created_at, ip_address
search for ip in db on new vote and see if time diff greater than allowed vote time limit between user votes
use CAPTCHA every variable number of votes to ensure human
calculate current vote count by counting all the entries for an entity for a contest
2) Contest model: start and end datetime
have a weekly or monthly cron job create the newest instance
votes find current contest if current date in between these 2 dates
individual model allows to create attributes to the contest(for example, special kinds of contests)
3) Winner model: contest_id, entity_id
allows for users to comments on past contest winners

Without knowing more details, I would go with something along the lines of:
class User
has_many :votes
has_many :comments
has_many :contests, :through => :votes
class Vote
belongs_to :user
belongs_to :contest
class Contest
has_many :votes
has_many :users, :through => :votes
class Comment
belongs_to :user
This way, you can have #user.votes, #contest.votes, #contest.users, etc.
I don't see the need for a Winners model, since that can just be a boolean in Users. If you needed to, you could always have a Winnings model that belonged to both Users and Contests to link the two.
Hope that helps.

Related

Finding the most in a has_many relationship with an extra condition

I have a Users model that has many Polls. The Polls can be the same amongst users. The Poll model has many votes. The User Model also has many votes. The Vote model has User ID, Poll ID, and option chosen. I want to, for a given user, find the poll with the most votes.
I was looking counter_cache, but I'm not sure how to apply it to this problem. Is there a better way to solve this than iterating through each poll a user has and seeing the largest count where used_id = user_Id?
Yes, you could do this with the counter_cache. On the polls table you'd have a column votes_count. Your migration could look like this:
add_column :polls, :votes_count, :integer, default: 0
and the approach for finding the record would be:
class User
has_many :polls
has_many :votes
end
class Poll
has_many :votes
end
class Vote
belongs_to :user
belongs_to :poll, counter_cache :true
##attr :option_chosen
end
If you had some records before adding the table you need to reset the counters.
Now, to fetch the poll with the most votes, you could easily do:
User.first.polls.order(votes_count: :desc).first
Hope that helps.

Get all associated data for all records of a model type in Rails?

How do I meld together getting all of the associated data for all of the records of a given model?
I have the following models:
User --N:1--> Reservation <--1:N-- Concert
So pseudo-code:
Reservation belongs_to User
Reservation belongs_to Concert
User has_many Reservations
User has_many Concerts through Reservations
Concert has_many Reservations
Concert has_many Users through Reservations
How do I make a single big array of everything?
I can get all my Reservations via Reservation.all
I can get the User for a particular Reservation via Reservation.find(25).user
I can get the Concert for a particular Reservation via Reservation.find(25).concert
But how do I get it for all of them? If I do
Reservation.all.each do |res|
res.user.name+","+res.concert.name+","+res.concert.date # etc.
end
Then it will do two new database queries for each reservation as it loops through. For 10 records, it might not matter, but for thousands, it can be very painful. Add to it other associations (e.g. Concert belongs_to venue, User has_one email, etc.)...
Is there any way to say, "Get all of the reservations and the following attached info" so it loads in a single SQL query?
What you're trying to accomplish is called eager loading, and can be done using includes in ActiveRecord. See below:
N + 1 queries problem
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
In your example you could use the following:
Reservation.all.includes(:user, :concert)
It is also a good idea to specify the :inverse_of option for your :belongs_to relations. This optimizes object loading and makes sure that cross-referencing a model will point back to the same object in memory, i.e.:
#user == #user.reservations.first.user # true
More information available here:
If you are using a belongs_to on the join model, it is a good idea to set the :inverse_of option on the belongs_to ...
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
In your example:
# app/models/reservation.rb
belongs_to :user, :inverse_of => :reservations
belongs_to :concert, :inverse_of => :reservations

Rails: Marking content as complete for individual users, when content is common across them

I'm relatively new to Rails, so apologies in advance if this is an obvious question. I could not find an answer through searching.
I'm building a basic application which acts as an educational course - users can view lessons, take in the content, and mark lessons as 'complete' accordingly.
I would like users to be able to see which lessons are complete, by marking them as such in the course overview.
I have a Users model and a Lessons model, and the lessons are identical per user at present. If lessons were unique per user, this would presumably be solvable with a boolean 'complete' column for each lesson. This is not the case in this application, however - some users will have completed a lesson; others will not have.
How would I best go about a solution to this? All suggestions and ideas welcome.
Use many-many association and establish relationship among the 3 models.
class Student < ActiveRecord::Base
has_many :progresses
has_many :subjects, through: :progresses
end
class Subject < ActiveRecord::Base
has_many :progresses
has_many :students, through: :progresses
end
class Progress < ActiveRecord::Base
belongs_to :student
belongs_to :subject
end
To be precise use this link to get good understanding on many-many association :)
Third model, say Progress or Completion or Grades or UserLessons... that will belong to user and lesson, and have a field called complete or score or grade....
It's a classic case of many-to-many relation.
User can read multiple lessons
Lessons could be read/complete by multiple users
So to do this is to create another model with column user_id lesson_id as a foreign key for user and lesson and create an additional column completed boolean

how to relate this data?

In my app, a subject has_many goals and each goal belongs to a subject.
This relationship makes the most sense, but I'm wondering how to use it in practice. For example - after a given time frame, each subject's goals should be evaluated, but they'll be evaluated on a student-by-student basis.
so let's say
goal.1 = "drink an entire gallon of milk without vomiting"
student.1 = "Lisa"
And let's also say Lisa is really quite good at holding her bile - so for goal.1, Student.1 = 5. Goals are tied to subjects, so I know that goal.1 belongs to English, Math, etc, but what's the best way to model the relationship that goals have to students when the students are being evaluated? They should also be able to be evaluated several times in a given period.
I think the following covers your description:
Subject
has_many :goals
end
Goal
belongs_to :subject
has_many :evaluations
end
Student
has_many :evaluations
end
Evaluation
belongs_to :goal
belongs_to :student
# columns: score, date
end
The evaluation object allows a student to have many evaluations for many goals over a period of time.

Querying complex data in Rails 3.0

I have a data model where users have timelogs (which have dates).
I'm trying to query my DB in a way that will let me spit out a table of data, listing each user that has timelogs, and the sum of the time logged for each day in the period queried (similar in essence to a weekly timesheet).
I'm having problems figuring out a way of doing this. Any ideas?
A lot of the details will depend on your data model, but the short answer is to create a relationship first:
class User < ActiveRecord::Base
has_many :user_timelogs
has_many :timelogs, :through => :user_timelogs
end
class UserTimelog < ActiveRecord::Base
belongs_to :user
belongs_to :timelog
end
class Timelog < ActiveRecord::Base
has_many :user_timelogs
has_many :users, :through => :user_timelogs
end
Once you do that, you can query timelogs for users:
User.all.timelogs
You can add on additional queries (specific dates, sums, etc.). Check out the Rails guides for more info on how to narrow down that query:
http://guides.rubyonrails.org/active_record_querying.html
Try this, assuming the times are stored as number of seconds in a 'duration' column for each timelog row:
Timelog.where(...). # your time period
joins(:users).
group('users.id').
sum('duration')
This will give you a hash with the user ids as keys, and the sum of the durations as values.

Resources