How to use joint query in this association - Ruby on Rails - ruby-on-rails

I am working in ruby 2.1.5 and rails 3.2.1. I want to list all the company in grid which is associated to company_name = John
Company table:
company model:
has_many :partner_relationships, :class_name => "CompanyRelationship",:foreign_key => 'partner_id',
company_relationships table:
I want to get all the company information from company table where company.id = partner_id. I tried the below query
Company.joins(:partner_relationships).where('company_relationships.partner_id' => company.id)
This is returning 3 set of same data that is <#id:2, company_name:John, description:I am John#>
I want to return the records as follows <#id:1, company_name:Jose, description:I am Jose#>, <#id:3, company_name:George, description:I am George#>,..<#id:5, company_name:Alwin, description:''#>
Please help me in solving this.

Shouldn't you use "partner_id"?

Related

ActiveScaffold or ActiveRecord how to search on an associated model's column

I have following models
Customer: name:string, phone:string
has_many :sales
Sale: amount:float, item_name:string
belongs_to :customer
Now in ActiveScaffold I get a simple single line input box to search for sales.
What I need to do is, be able to search sales by the customer name as well.
There should be a way to do this with ActiveScaffold, or atleast with native active record functionality.
One way I can think of is, adding the customer name as a column and populate it along with sale while it is created.Not sure what the best approach to achieve this should be.
Edit: Adding info from comment:
Is it possible to define something like
Sales
searchable_columns :amount, :association => {:customer => name}, :as => yumyum_column
now when i search by
Sale.where(:yumyum_column => 1000)
or
Sale.where(:yumyum_column => "Customer name")
both will return the same record.
Try something like this:
# Sales Controller
config.columns[:customer].search_sql = "customers.name"
config.search.columns = [:item_name, :customer] # Search by sale's item_name or customers's name.
To show the customer name in the list of results try something like:
# Customer model
def to_label
name
end
# Sales Controller
config.list.columns = [:item_name, :customer]
For more info, see the API: Search page
If you have (and you should have) a customer_id in your sales table, then you can query sales with any customer attribute you like with a simple join:
Sales.joins(:customers).where(:'customers.name' => :john)
which translates to the following SQL
"SELECT `sales`.* FROM `sales` INNER JOIN `customers` ON `sales`.`customer_id` = `customers`.`id` WHERE `customers`.`name` = 'john'"

Newbie: Rails' way to query database in my case

I am using Ruby v1.8 and Rails v2.3.
I have a two model objects: Cars and Customers,
Model Cars:
class car < ActiveRecord::Base
#car has attribute :town_code
has_many :customers
end
Model Customers:
class customer < ActiveRecord::Base
# customer has attribute :first_name, :last_name
belongs_to :car
end
Now in my controller, I got a string from VIEW, and the received string has the format firstname.lastname#town_code, for example a string like "John.smith#ac01" which can be parsed as first_name="John", last_name="smith" and town_code="ac01"
Now I would like use the Rails's way to query the database to find all the customer objects (match the above conditions) from Customers table which has :
first_name="John",
last_name="smith"
and owned a car(by car_id) with car's town_code="ac01".
what is Rails' syntax to query this?
I know it should be something like (if I wanna count the nr of matched customer):
Customer.count :consitions =>{:first_name => "John", :last_name=>"smith"...}
But, I am not sure how to refer to a customer that has a referenced car with car's town_code= "ac01" ?
------------------ My question --------------------
I want to have two queries:
-one is used to count the number of matching customers,
-the other query returns the customers objects like find_by_ query.
What is the syntax in Ruby on Rails for the two queries?
It should be something similar to
Customer.where(:firstname => "John", :last_name => "Smith").count
If you have many Customers of Car, you can do something like
Car.where(...).customers.where(...)
You should really be firing rails c to test your queries in (I might be slightly off)
You could have something like:
#customers = car.where(:town_code => town_code).customers.where(:first_name => first_name, :last_name => last_name)
And then just count the results:
#customer_count = #customers.count
This assuming you parsed your string into the variables town_code, first_name, and last_name, like you said.
Edit
I don't think Rails v2.3 supports these chains of Active Record queries because I believe it lacks lazy loading from DB. I'm not completely sure. Also, I realize my first suggestion would't work because there could be many cars with the same town_code. I guess you could solve it using the map function like so (not tested):
#customers = car.all(:conditions => {:town_code => town_code}).map{ |c| c.customers.where(:first_name => first_name, :last_name => last_name) }
And then count them like before:
#customer_count = #customers.count
I believe you could do something like this: source
Customer.find(:all, :include => :car, :conditions => "customers.first_name = 'John' AND customers.last_name = 'Smith' AND cars.town_code = 'ac01'")
Counting all customers with a specification can be achieved by this command: source
Customer.count(:all, :include => :car, :conditions => "customers.first_name = 'John' AND customers.last_name = 'Smith' AND cars.town_code = 'ac01'")
By the way, if you are in the position to choose what you work with, I would advise you to go for Rails 3. The chaining methods described by Joseph would make this kind of query a lot easier and it'll save you upgrading issues down the road. (And you tagged the question for Rails 3)

How to create an active record search across models 3 levels deep?

Alright, database stuff is turning out to be my rails weakpoint.
I have 3 models I am trying to search across: User, Invoice, Payment
User has_many invoices and Invoice has_many payments.
I am trying to create a search that will find all of the payments for the current_user across a given date range.
This is how I have done this so far
invoices = current_user.invoices
payments = invoices.inject([]) {|arr,x| arr += x.payments.where("payment_date <= ? and payment_date >= ?", '2011-02-01', '2011-01-01')}
This seems insane to me. I'm sure there must be a way of getting this out of the database directly without iterating through results. Any ideas? Cheers in advance!
You should use something like :
Payments.joins(:invoice => :user).where("users.id = ? AND (payments.payment_date <= ? and payments.payment_date >= ?)", current_user.id, '2011-02-01', '2011-01-01')
You probably want to read the Ruby On Rails Guides about active record query
UPDATE:
From the guide linked, a more cleaner syntax will be :
time_range = (Time.now.midnight - 1.month)..Time.now.midnight
Payments.joins(:invoice => :user).where(:users => {:id => current_user.id}, :payments => {:payment_date => time_range})
UPDATE 2, another solution :
In your model User :
has_many :payments, :through => :invoices
To perform the query :
time_range = (Time.now.midnight - 1.month)..Time.now.midnight
current_user.payments.where(:payment_date => time_range)

How can I get a unique :group of a virtual attribute in rails?

I have several similar models ContactEmail, ContactLetter, etcetera.
Each one belongs_to a Contact
Each contact belongs_to a Company
So, what I did was create a virtual attribute for ContactEmail:
def company_name
contact = Contact.find_by_id(self.contact_id)
return contact.company_name
end
Question: How can I get an easy list of all company_name (without duplicates) if I have a set of ContactEmails objects (from a find(:all) method, for example)?
When I try to do a search on ContactEmail.company_name using the statistics gem, for example, I get an error saying that company_name is not a column for ContactEmail.
Assuming your ContactEmail set is in #contact_emails (untested):
#contact_emails.collect { |contact_email| contact_email.company_name }.uniq
You don't need the virtual attribute for this purpose though. ActiveRecord sets up the relationship automatically based on the foreign key, so you could take the company_name method out of the ContactEmail model and do:
#contact_emails.collect { |contact_email| contact_email.contact.company_name }.uniq
Performance could be a consideration for large sets, so you might need to use a more sophisticated SQL query if that's an issue.
EDIT to answer your 2nd question
If company_name is a column, you can do:
ContactEmail.count(:all, :joins => :contact, :group => 'contact.company_name')
On a virtual attribute I think you'd have to retrieve the whole set and use Ruby (untested):
ContactEmail.find(:all, :joins => :contact, :select => 'contacts.company_name').group_by(&:company_name).inject({}) {|hash,result_set| hash.merge(result_set.first=>result_set.last.count)}
but that's not very kind to the next person assigned to maintain your system -- so you're better off working out the query syntax for the .count version and referring to the column itself.

Trying to find a count of items from a two level deep association, any ideas?

I am working on an application where I need to find the count of submitted items by users that have been referred by a user.
For Example -
User1 has referred 3 people (User2, User3, User4) and each of those users has submitted 5 articles.
I am trying to find a way to get the count of submitted items in User1's tree (should be 15 in this case).
My user model looks like the following (simplified)
class User < ActiveRecord::Base
# Code for user referrals
belongs_to :referrer, :class_name => "User"
has_many :referrals, :class_name => "User", :foreign_key => "referrer_id"
has_many :items
end
I can find out the count for each user easily (User.items.size), but I am having trouble finding a solution to get the referral counts as one sum.
Any ideas?
Try this:
user = User.find(1)
total_items_size = user.referrals.map(&:items).flatten.size
You can use select_value to manually run the SQL query:
def referred_items_count
select_value("select count(*) as referred_items
from items inner join users on users.id = items.user_id
where users.referrer_id = #{self.id};", "referred_items")
end
The benefit is that it is a lot more scalable than using Ruby to count.
Get all items of User with id of 1
total = 0
Users.find(1).referrals.each do |refer|
total += refer.items.size
end

Resources