I have 3 models
class Company < ActiveRecord::Base
has_many : CompanyAccount
has_many : CompanyContact
end
class CompanyContact < ActiveRecord::Base
belongs_to : Company
end
class CompanyAccount < ActiveRecord::Base
belongs_to : Company
end
As both the CompanyAccount and CompanyContact models belong to the Company model, they have a similar "company_id" field. I have retrieved some Accounts through a query:
#CompanyAccounts = CompanyAccount.where.not(balance:nil)
Now, using the common company_id field I am trying to retrieve all the data from my CompanyContacts table that belong to the same Company associated with the CompanyAccounts I queried above (in other words, I am trying to get the rows which have the same company_id). I have made several attempts using "joins" but everything failed so far. Could anyone give me what would be the appropriate syntax in this context? Thanks.
First things first, please pay attention to proper Ruby naming conventions. Ruby classes and modules should use CamelCase while symbols, methods, and variables should all use snake_case. Given this, I would re-write your models as follows
class Company < ActiveRecord::Base
has_many: company_accounts
has_many: company_contacts
end
class CompanyContact < ActiveRecord::Base
belongs_to: company
end
class CompanyAccount < ActiveRecord::Base
belongs_to: company
end
Now, onto your question. I would use includes to eager load the associated company and it's associated contacts. For example
#company_accounts = CompanyAccount.includes(company: :company_contacts).where.not(balance: nil)
What this will do is for each company account with a balance, it will load it's associated company and the company's associated contacts into memory so that you can access it
#company_accounts.each do |account|
# access to the company
account.company
# access to the company's contacts
account.company.contacts
end
Hope this helps.
Related
I am currently making a website that runs on Ruby on Rails. I am facing some issues while I was trying to join two tables, Rates and Locations, that I have with two different attributes name.
Rates: id rater_id rateable_id (and a few more attributes in this table)
Locations: id title body user_id (and a few more attributes in this table)
Here is the query that I am trying to do in SQL.
SELECT *
FROM rates, locations
WHERE rates.rater_id = locations.user_id AND rates.rateable_id = locations.id
I have read the official active record documents that provided by rubyonrails.org. I have tried doing these, but it does not work. Here is the code that I am trying to implant in app\controllers\users_controller.rb
#join_rating = Rate.joins(:locations).where("rates.rateable_id = locations.id AND rates.rater_id = locations.id")
#all_rating = #all_rating.where(rater_id: #user)
#count_all_rating = #all_rating.count
#join_rating, is trying to join the attributes with different names.
#all_rating, is trying to filter which location to show using the user ID
#join_rating, is trying to calculate the total numbers of locations that are rated by the user
Assume that everything is setup correctly and the only error is in the query that I am trying to do, how should I rewrite the statement so that I am able to show the locations that the user has rated using #all_rating.
Thank you!
A few points:
When in ActiveRecord you're starting a statement with the Rate class, it means the result is going to be a collection of Rate objects. So if you're trying to show locations, you should start with a Location class.
#locations_user_rated = Location.joins('INNER JOIN rates ON
rates.rateable_id = locations.id').where('rates.rater_id' => #user)
And if your ActiveRecord associations are well defined, you could simply do:
#locations_user_rated = Location.joins(:rates).where('rates.rater_id' => #user)
"Well defined" simply means you'll need to do something like the following. Note that I am not sure I understand your model relationships correctly. I assume below that every location has multiple rates, and that the reason your Rate model has the field called rateable_id instead of a location_id is because you want :rateable to be polymorphic. This means you probably also have a rateable_type field in rates table.
class Location < ActiveRecord::Base
has_many :rates, as: :rateable
end
class Rate < ActiveRecord::Base
belongs_to :rateable, polymorphic: true
end
If this polymorphism is not the case, things should actually be simpler, and I highly recommend that you follow Rails's conventions and simply name the relationship field location_id on your Rate model instead of rateable_id. Then you can do:
class Location < ActiveRecord::Base
has_many :rates
end
class Rate < ActiveRecord::Base
belongs_to :location
end
If still you are not convinced about the field name, you can customize things and do:
class Location < ActiveRecord::Base
has_many :rates, foreign_key: :rateable_id
end
class Rate < ActiveRecord::Base
belongs_to :location, foreign_key: :rateable_id
end
You can find more about how to customize associations here, and here.
I highly recommend taking advantage of ActiveRecord's has_many, belongs_to, and has_many through: functionality.
If you set up a model for each of these tables, with the correct relationships:
class User < ActiveRecord::Base
has_many :ratings, foreign_key: :rater_id
has_many :rated_locations, through: ratings, class_name: Location.name, source: :rater
end
class Rating < ActiveRecord::Base
belongs_to :rater, class_name: User.name
belongs_to :location
end
class Location < ActiveRecord::Base
has_many :ratings
end
Then to access the locaitons that a user has rated, you just call
user.rated_locations
Here is my STI Models:
class User < ActiveRecord::Base
end
class Athlete < User
has_many :sports, :through => :user_sports
has_many :user_sports
end
class Coach < User
end
The UserSports table has user_id and sport_id... but then you run this:
athlete = Athlete.all.last
athlete.sports
The SQL that is generated is trying to use the athlete_id instead of the user_id... not too sure what I am doing wrong here... any suggestions would be greatful!
I'm not sure why you have a UserSports table. You can just use a foreign key for either User or Sport, depending on their relation to each other.
The User model would need a specified relation to the Sport model, and vice versa.
More information on that is here: http://guides.rubyonrails.org/association_basics.html#the-has_many-association
It makes sense that it's trying to pull the athlete_id instead of the user_id, since you are calling on an Athlete object.
As a side note: There is no need to write Athlete.all.last - you only need to write Athlete.last.
I need to set up a multiple class inheritance model here for the following models. Basically I'm building an extensible contacts directory. From a base class Contact I intend to derive other classes i.e something on the lines of :
class Contact
# the super class
attr_accessible :name, :about
end
class Person < Contact
attr_accessible :first_name, last_name, :description, :works_for_company_id
end
class Company < Contact
attr_accessible :company_name, :location, :services
end
Each model corresponds to a different table - I'm assuming that there would be a has_one belongs_to relation ship between teh parent and the child classes however I was wondering if theres a gem that can ease it a bit. Or if I have to do it myself how would I actually accomplish it.
For example contact.name is actually person.first_name+' '+person.last_name for a person or company.company_name for the company. How do I structure my database and associations to get this right?
I've seen some posts dealing with this, and am trying to determine the best solution.
Semantically, I want a Client model with a one-to-one relationship with a Survey. There are different kinds of surveys that have different fields but I want to share a significant amount of code between them. Because of the different fields I want different database tables for the surveys. There is no need to search across different types of surveys. It feels like I want the foreign key in the Client table for fast retrieval and potential eager-loading of the Survey.
So theoretically I think I want polymorphic has_one and multiple inheritance something like this:
class Client < ActiveRecord::Base
has_one :survey, :polymorphic => true
end
class Survey
# base class of shared code, does not correspond to a db table
def utility_method
end
end
class Type1Survey < ActiveRecord::Base, Survey
belongs_to :client, :as => :survey
end
class Type2Survey < ActiveRecord::Base, Survey
belongs_to :client, :as => :survey
end
# create new entry in type1_surveys table, set survey_id in client table
#client.survey = Type1Survey.create()
#client.survey.nil? # did client fill out a survey?
#client.survey.utility_method # access method of base class Survey
#client.survey.type1field # access a field unique to Type1Survey
#client2.survey = Type2Survey.create()
#client2.survey.type2field # access a field unique to Type2Survey
#client2.survey.utility_method
Now, I know Ruby does not support multiple inheritance, nor does :has_one support :polymorphic. So is there a clean Ruby way to achieve what I'm getting at? I feel like it's right there almost...
Here's how I would do this:
class Client < ActiveRecord::Base
belongs_to :survey, :polymorphic => true
end
module Survey
def self.included(base)
base.has_one :client, :as => :survey
end
def utility_method
self.do_some_stuff
end
end
Type1Survey < ActiveRecord::Base
include Survey
def method_only_applicable_to_this_type
# do stuff
end
end
Type2Survey < ActiveRecord::Base
include Survey
end
I have been reading about Active Record Associations on RailGuides and I have found it very informative but I definitely need help with understanding some of the choices. Still learning.
I have a Client model with the following attributes:
name
birth_date
address1
etc
Then a Contract model with these attributes:
auth_num
start_date
end_date
client_id .... I think I need this here for the new contract form
Also, a Code model with these attributes:
code_name
status
description
I have a join table ClientLines with these attributes:
Contract_id
Client_id
And a join table CodeLines with these attributes:
Contract_id
Code_id
Client_id
Units_Alloc ... each contract might use a combination of codes some of which are
the same in other contracts but they have different number of units
allocated.
I am tempted to use the Polymorphic association because the Contract model is associated with the Client Model and the Code Model, but I am not confident enough to go ahead and set this up without first checking if someone is willing to give me some guidance on the examples I have listed?
My hope for guidance rests around these questions.
Is the polymorphic association the best choice for the example of models I have listed above?
Since Contracts use different combinations of Codes, but some of the Codes are the same in other Contracts with the only difference being the number of units allocated, do I have units allocated in the correct table? (Essentially I do not know where to put units alloc?)
When I set up the data-entry form such that I can enter in new contracts which will pull in specific attributes from the client table and code table, is it appropriate to have Client_id listed as one of the attributes of the Contract model and of course the units alloc attribute still looms large in my mind as a problem, where do I pull it from?
Any help or pointers would be most helpful.
Thanks.
Well, I'll give it a try :)
I understand, that we come from a Contract, that is a signed by one client and is about some "Codes". So it can go like this:
class Contract < ActiveRecord::Base
has_one :client
has_many :codes
end
class Client < ActiveRecord::Base
belongs_to :contract
end
class Code < ActiveRecord::Base
belongs_to :contract
end
Where you store contract_id in clients table and in codes table. Then you can do AR operations like:
contract = Contact.find_by_auth_num(1234)
contract.client #gets you the client
contract.codes #gets you contracted codes
contract.codes.count #gets you number of contracted codes
Or if you want it more sophisticated you can change the relation to
class Contract < ActiveRecord::Base
has_one :client
has_many :contract_codes
has_many :codes, :through => :contract_codes
end
class Code < ActiveRecord::Base
has_many :contract_codes
has_many :contracts, :through => :contract_codes
end
with intermediate model of
ContractCode < ActiveRecord::Base
belongs_to :code
belongs_to :contract
end
where you can store number of codes in a special column. Of course, all these declarations has to be backed up by proper migrations :) Did I clear things a bit?