Having issues building a rails query that includes three associated models - ruby-on-rails

I have three models I'm working with: User, Deal, and Investment.
User
User has many :deals
User has many :investments
Deal
Deal has many :investments
Deal belongs to :user
Investment
Investment belongs to :user
Investment belongs to :deal
(these are the only associations I have set up between these models)
Lets say I have a User record 'u', and Deal has an attribute called funding_type_id.
I want to find all investments made by user 'u' where the investment.deal.funding_type_id == 3.
Or to be more clear: Investments are made on a deal by a user. I was the set of investments made by user 'u' on deals who's funding type id is 3.
I posted this awhile ago, but didn't receive any successful responses. I've made several attempts on my own since then, but all have been met with failure, so I'm back to SO. Hopefully I explained my question clearly. Thanks!

EDIT: My bad, misread the question -- early morning after a late night :)
Try this instead:
investments = Investments.joins(:deal).where(user_id: u.id, deals: { funding_type_id: 3 })
That should generate the following SQL (subbing in 1 for u.id):
SELECT "investments".* FROM "investments"
INNER JOIN "deals" ON "deals"."id" = "investments"."deal_id"
WHERE "investments"."id" = 1 AND "deals"."funding_type_id" = 3
Which should give you the rows you want.
If you set up a has_many :through association (see the Association Basics guide) between User and Deal, you can directly access all the deals belonging to a user:
# user.rb
has_many :deals, through: :investments
You can then get all the deal for a particular user using:
user_deals = User.deals
You can optionally put a where condition on that to limit it the way you want. Where u is the user you want the deals for:
deals = u.deals.where(funding_type_id: 3)

Related

Looking for a way to track history in rails database

I'm considering this an add-on question of sorts to the thread below:
Using join tables in ruby on rails
So we have 'Student' and 'Course' scaffolds joined by a many-to-many association, but in addition there is also a 'Semester' scaffold and what I wish to do is, for each student that is added to a course, for the application to search for previous iterations of the same course through past semesters, to that it's known how many times a student has taken that class before. I'm kind of mixed up at the moment as to how to implement this, so I was hoping someone could help me pin down the logic and code I should be operating by.
Some underlying assumptions I have so far:
'Course' and 'Semester' should, like 'Student' and 'Course', be joined
by a many-to-many association (many courses are taught per semester,
and a course is taught for more than one semester).
There should be an action (let's say get_student) within the course
controller to locate the student via student_id. This would be the main area I'm scratching my head as to what to do. What would this method look like in code?
Within the student-course join table I should have an attribute
'attempts' which increments each time get_student finds this
student_id combined with the course_id that calls the method.This
would be the mechanism that actually tells how many times the course
had been attempted by the student.
I initially wondered if there should be a 'semester' controller
action to activate get_student across all semesters, but now I'm
thinking that get_student should work fine without that.
Appreciate any help I can get on this. Thanks.
This is not a good answer, just a comment.
I would comment, but hear will be more clear. I ll update for the other points. This is just an ongoing feedback/discussion, not an answer.
class Semester < ApplicationRecord
has_many :courses
end
class Course < ApplicationRecord
has_many :students
end
And
semester.courses[0].students => outputs the students array for that
This could be the method to calculate the number of student that did that course:
def studentForCourse
#input_params.course_id => course id you are selecting
semester = Semester.find(input_params)
semester.courses.each do |course|
if course.id = input_params.course_id
nstudents = course.students.size
end
end

Rails, find by association

I'm about to build a messaging feature for a rails app.
I thought about having conversations, conversation_participants and conversation_messages.
Which means:
Conversation:
has_many :conversation_participants
has_many :conversation_messages, through: :conversation_participants
Conversation Participant:
belongs_to :conversation
belongs_to :user
has_many :conversation_messages
Conversation Message:
belongs_to :conversation_participant
So far, so good.
I'm just stuck in some scenarios:
How do I find the conversation for User 1 and User 2?
How do I find one for User 1, User 4 & User 5?
What if there are two conversations, one for Users 1,4,5 and one for 1,4,5,6 but I'm just looking for 1,4,5?
Hope somebody could help me out on this one! Thank you!
You can exclude converstion_messages. These are irrelevant, and need to include users.
#user
has_many :conversations, through: converstion_participants
user_12_conv_ids = user_1.conversation_ids & user_2.conversation_ids
user_123_conv_ids = user_12_conv_ids & user_3.conversation_ids
user_123_conversations = Conversation.where(id: user_123_conv_ids)
Now you can select conversations that include only 1, 2, and 3 (as user_ids)
conversations.select{|c| c.user_ids == user_ids}
You may want to look more into the merge and where methods.
The first example would look something like:
Conversation.joins(:conversation_participants).merge(User.where(:id => user1_id)).merge(User.where(:id => user2_id))
Each merge() filters the results. You wouldn't want to use merge(User.where(:id => [user1_id, user2_id])) because you would get all the conversations for both users, not just the common ones.
The second example would be similar to the first one.
In the third example you could add something like .merge(User.where.not(:id => user6_id) at the end of the query to not include conversations with User 6.
UPDATE
To chain multiple merge dynamically you could try something like:
conversations = Conversation.joins(:conversation_participants)
user_ids.each{|uid| conversations.merge!(User.where(:id => uid))}
It sounds like you will want to set up an association between users and conversations through conversation participants.
How do I find the conversation for User 1 and User 2?
This doesn't seem to be a unique conversation given the way you've set things up. Users 1 and 2 could be in one conversation with only each other, and another conversation that includes other participants. That being said, if you join the conversation_participants table to itself on conversation_id you should be able to find the matches. There are other ways to go about this to and I'm happy to provide more info. The way you decide to approach this will factor into the answers to your other questions as well.
UPDATE:
The query would look something like this:
SELECT cp1.conversation_id
FROM conversation_participants as cp1
JOIN conversation_participants as cp2 ON cp1.conversation_id = cp2.conversation_id
WHERE cp1.participant_id = 1 and cp2.participant_id =2;

Rails associations - orders

So I have been trying to create a dummy application to try and learn Rails. The app I thought I could create is a coffee ordering app for a group of people in work.
So the website will have many users.
A user can create a coffee_order.
A coffee order contains orders for other individual users.
Each user can have one or more coffee_shop_items (e.g. latte,
cappuccino,danish, muffin, etc)
A coffee order also has an assignee, this is the person who is tasked
with going and getting the order.
So as a user, I create a coffee order, select an assignee, add users to the order, and add one or more coffee shop items to each user,
I am really struggling with how the database should be, and what the associations need to be, along with any join tables?
I am also trying to use nested attributes for the form entry.
Thanks in advance for help.
Update with some code I have tried to create a coffee order:
#coffee_order = CoffeeOrder.new(coffee_order_params)
params[:coffee_order][:user_coffee_orders_attributes].each do |user_order|
order = #coffee_order.user_coffee_orders.new(user_id: user_order[1][:user_id].to_i)
user_order[1][:coffee_shop_items].each do |item|
coffee_shop_item = CoffeeShopItems.find(item) if item != ""
# this line fails! see error below
#coffee_order.user_coffee_orders.coffee_shop_items << coffee_shop_item if coffee_shop_item != nil
end
end
error:
NoMethodError (undefined method `coffee_shop_items' for #<UserCoffeeOrder::ActiveRecord_Associations_CollectionProxy:0x42c6180>):
The coffee_shop_items belong to the order, not the user. After all, a user could probably create another order another day? You should probably also check out the rails documentation, which, IIRC actually contains a walk-through of a shopping cart application.
User has_many :coffes_orders
User has_many :coffee_orders_he_needs_to_get, class_name: "CoffeeOrder", foreign_key: "assignee_id"
CoffeeOrder belongs_to :user
CoffeeOrder belongs_to :assignee, class_name: "User"
CoffeeOrder has_and_belongs_to_many :coffee_shop_items
Coffee_shop_items has_and_belongs_to_many :coffee_orders

Recording a sports team's matches - a many-to-many relationship?

I am new to Ruby on Rails, but I have created a few simple apps in the past. Now I am doing something a little more complex and I am stumped on database design.
I am creating a sports league manager and I need some advice on how the relationship between teams and games is modelled to point me in the right direction. Every time a game is played between two teams, the match is recorded. I'd like to be able to do the following:
1) On a specific team's page, I would like to show a list of matches the team has participated in.
2) I would like to keep a record of each team's wins, losses, and ties to show on a league standings page.
On point #1 I figured this would be a many-to-many relationship, that is, a Team has many Matches, and a Match has many Teams (well, just two actually). The point I am a bit stumped on is how and where to store the stats for each team. Where do I keep the wins/losses/ties? Are they part of the Team table? If so, if I was to have a page with team standings showing each teams w/losses/ties, how would I get that information?
This isn't really finished, but maybe this will help you or someone else get the ball rolling here.
I'm focusing on just how to structure the relationship between Teams and Matches. At least part of the solution lies in using a polymorphic association, I believe, and part of it would perhaps be a self join. I swear it's right in front of me and I'm not seeing it.
Taking baby steps here, assuming you have a table like this for your Matches tableā€¦
id | home_team_id | away_team_id | home_team_score | away_team_score
You can set that up in your models with these associations:
class Match
belongs_to :home_team, :class_name => :team
belongs_to :away_team, :class_name => :team
end
class Team
has_many :home_matches, :foreign_key => :home_team_id, :class_name => :matches
has_many :away_matches, :foreign_key => :away_team_id, :class_name => :matches
end
The obvious problem there is that there are two relationships when there really should only be one. That's why I think a polymorphic association can help, but this is sort of convoluted.
See the Rails guide on polymorphic associations and see if that helps you see what I can't.
I would suggest against creating a traditional many-to-many relationship here. Instead, you'd have just two tables: Teams and Matches.
Each team would be identified by a row in Teams and would have a unique identifier, such as TeamId.
The Matches table would the following columns:
MatchId - a synthetic primary key
SeasonId - identifies the season the match took place in
HomeTeamId - the home team
VisitngTeamId - the away team
HomeTeamScore
VisitngTeamScore
... Any other statistics you'd want to keep for an individual match
I presume you have the notion of home and visiting teams. If not, you can just name these columns Team1Id and Team2Id, or something along those lines.
The point I am a bit stumped on is how and where to store the stats for each team. Where do I keep the wins/losses/ties?
The wins, losses, and ties are implicit in the Matches table - you can query that to get back a team's record. For instance, the following query returns the wins, loses, and ties for team X:
-- Wins
SELECT COUNT(*)
FROM Matches
WHERE SeasonID = #SeasonID AND
(HomeTeamId = X AND HomeTeamScore > VisitingTeamScore) OR
(VisitingTeamId = X AND VisitingTeamScore > HomeTeamScore)
-- Loses
SELECT COUNT(*)
FROM Matches
WHERE SeasonID = #SeasonID AND
(HomeTeamId = X AND HomeTeamScore < VisitingTeamScore) OR
(VisitingTeamId = X AND VisitingTeamScore < HomeTeamScore)
-- Ties
SELECT COUNT(*)
FROM Matches
WHERE SeasonID = #SeasonID AND
(HomeTeamId = X OR VisitingTeamId = X)
AND VisitingTeamScore = HomeTeamScore
Even if you wanted to denormalize the data model and store this information for each team, you wouldn't want to do it in the Teams table because you may want to know how many wins/losses/ties a team has for a given season. (I presume a team may stick together through multiple seasons. If this is not the case, disregard.)
I'm going off-the-cuff here, but consider:
tblTeam
TeamID
TeamName
. . . OtherTeamFields
tblMatch
MatchID
MatchDate
MatchLocationID
. . . OtherMatchFields
tblTeam_Matches
TeamID FK on tblTeam.TeamID
MatchID FK on tblMatchID
TeamStanding (Win, Loss, Tie)
The structure above has some pros and cons. On the pro side, the outcome for each team involved in a match is stored properly with the team's relationship to that match. One can retrieve the results for each team through a range of matches by setting criteria for TeamID and TeamStanding (i.e. "WHERE TeamStanding = "Win").
However, there is a more complex, but probably more scalable and usefull way, where you would define a TeamScore field for tblTeam_Matches. In this case, the Match winner would be determined by a rather difficult series of sub-queries (By difficult, I mean difficult for ME. I am betting there are folks here on SO who could pop a smaple out quickly . . . But it is a bit of a brain-teaser).
I believe the second option would be a more "proper" way to do it, but I messed with puling some version of:
StatsQuery:
TeamName
TotalMatches
Wins
Losses
Ties
I had a difficult time of it. Correlated sub-queries are NOT my strong point (yet).
Anyway, hope that gives you some food for thought . . .
I think this can be done using following way
class Team < ActiveRecord::Base
has_many :games
has_many :matches,:through => :games
end
class Matche < ActiveRecord::Base
has_many :games
has_many :teams,:through => :games
end
class Game < ActiveRecord::Base
belongs_to :team
belongs_to :match
end
and if you need to find total matches played by any team then
= team.games.count
if you need to find total won matches by any team then
= team.games.where(:winner => true).count

Rails: Relationship between two loosely related models

I am working on a Ruby on Rails 3 web application and am not sure how to relate two of the models.
In our organization sales reps go out on appointments. If the appointment is successful, it will result in creating an order (which then has the items ordered related to it, but that's for another day.) If this appointment is not successful, it will be marked as no sale and as you might have guessed, no order is created.
On the other hand, sometimes sales happen without an appointment. For example, a customer may call into the store and order something. In this case, an order can exist without an appointment.
It would be simple if there were no relationship between orders and appointments, but there has to be for ease of use for the end user. For example, if an appointment generates an order, but later the buyer cancels, they will mark the appointment as sale cancelled and then the system should automatically set the order as cancelled. Likewise,they may choose to cancel the order, then the appointment would have to be cancelled automatically by the system.
How does a developer handle something like this? Does the appointment :have_many => orders? does the order :belong_to => appointments? I don't know what to do!
Please help me with this, I am a pretty new rails developer and I feel in over my head! Thank you!
As you already said, the following will work fine:
class Appointment < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :appointment
end
belongs_to requires the field appointment_id to be present in the orders table. But, if the order is not associated with an order then appointment_id does not need to be set. You can have multiple belongs_to associations for a given class.

Resources