Group Query in Rails involving associations - ruby-on-rails

I have two tables (and associated models) in my Rails database with a one-to-many relationship.
billable_totals
---------------
id
project_id
adjusted_amount
projects
---------
id
project_type
The associated models are BillableTotal and Project with the following relationships:
BillableTotal belongs_to Project
Project has_many BillableTotals
I want to do a group query which outputs the project_type from projects table and the sum of adjusted_amount from billable_totals grouped by project_type. I am running into all sorts of problems. Both activerecord and Postgres keep complaining. Please advise on how to structure this query.

I think this should work:
Project.joins(:billable_totals).group(:project_type).sum('billable_totals.adjusted_amount')
I could at least run a query on that format in my own project and get reasonable results.

Related

Joining two tables that share the same id

Let's say I have two tables: NormalClass Table and SpecialClass Table.
Each table contains classes for students.
I want to join tables so that I can access the normal classes of each student in that has a special class for students.
Both tables share the student_id key.
Trying to do this:
NormalClass.includes(:specialClasses)..
results in:
ActiveRecord::ConfigurationError: Association named 'specialClasses' was not found on NormalClass.includes; perhaps you misspelled it?
Should I be doing something else?
Gerbil,
Basically, you need to first set your associations properly.
Look at section 2.4 The has_many :through Association in Rails guides
Once you set it, you can pull up the data you want by pulling the student_id key

Rails HABTM: Select everything a that a record 'has'

I have three tables: projects, technologies, and projects_technologies (a map from project IDs to/from technology IDs). I have two models: projects and technologies. Projects have and belong to many (HABTM) technologies and vice versa. Now I'm trying to get all the names (or active records, if there's a way to do that) of technologies that belong to a given project. Here's the SQL statement I've made, using 5 as the given project ID:
SELECT name FROM technologies WHERE id IN (
SELECT projects_technologies.technology_id FROM projects_technologies
WHERE projects_technologies.project_id = 5
);
I could just connect to the database and run the query, but since I already have the models set up with HABTM relationships, I'm wondering if there's a "Rails way" to execute this. I've been looking at this documentation, http://guides.rubyonrails.org/active_record_querying.html, but I can't figure out if and how I can apply that to this kind of query.
UPDATE
Turns out all I needed was this:
Project.find(5).technologies
The equivalent active record query would be
Technology.select('name').where("id IN (?)", ProjectTechnology.where("project_id = ?", 5).pluck(:technology_id))
Hope this helps!

How to search on joining table in Rails 3 which doesn't have a model?

I have two models merchant and category with a HABM relationship so have a joining table called categories_merchants
How can I write the following query in ActiveRecords?
SELECT
categories_merchants.merchant_id
WHERE
categories_merchants.category_id IN (1,2,3,4)
NOTE: The joining table doesn't have a model, it works automatically in Rails 3 without need for one.
If you want to do such a query you should transform your HABTM in a has_many :trough and create a model for the joining table and query based on that.
Alternatively, but possibly with worse performance, you could do:
Merchant
.select(:id)
.joins("categories_merchants ON categories_merchants.merchant_id = merchant.id")
.where("categories_merchants.category_id IN (?)", [1,2,3,4])

Rails 3 sorting through parent association

I have a fairly straightforward question in Rails 3 to which I can't seem to find the answer:
Let's say I have 2 models: Customer, Project.
A Customer has_many projects
Project belongs_to customer
Now I want to sort a list of projects by "customer name" using Active Record (doing it with a Ruby array is easy enough, but I imagine this will get problematic once the number of project records grows).
How do I go about doing this with ActiveRecord?
Project.joins(:customer).order('customers.name')

Rails ActiveRecord Relationships

How do the relationships magically function when only the models are altered?
If I want a "has__and___belongs___to__many" relationship, what should I name the table (so Rails can use it) that contains the two foreign keys?
Short answer: You can't just tell the models that they're related; there have to be columns in the database for it too.
When you set up related models, Rails assumes you've followed a convention which allows it to find the things you wrote. Here's what happens:
You set up the tables.
Following conventions in Rails, you name the table in a particular, predictable way (a plural noun, e.g. people). In this table, when you have a relationship to another table, you have to create that column and name it in another predictable way (e.g. bank_account_id, if you're relating to the bank_accounts table).
You write a model class inheriting from ActiveRecord::Base
class Person < ActiveRecord::Base
When you instantiate one of these models, the ActiveRecord::Base constructor looks at the name of the class, converts it to lowercase and pluralizes it. Here, by reading Person, it yields people, the name of the table we created earlier. Now ActiveRecord knows where to get all the information about a person, and it can read the SQL output to figure out what the columns are.
You add relationships to the model: has_many, belongs_to or has_one.
When you type something like, has_many :bank_accounts, it assumes a few things:
The name of the model that you relate to is BankAccount (from camel-casing :bank_accounts).
The name of the column in the people table which refers to a bank account is bank_account_id (from singularizing :bank_accounts).
Since the relationship is has_many, ActiveRecord knows to give you methods like john.bank_accounts, using plural names for things.
Putting all of that together, ActiveRecord knows how to make SQL queries that will give you a person's bank accounts. It knows where to find everything, because you followed a naming convention that it understands when you created the table and its colums.
One of the neat things about Ruby is that you can run methods on a whole class, and those methods can add other methods to a class. That's exactly what has_many and friends are doing.
This works because you are following "Convention over Configuration".
If you state that a customer model has many orders then rails expects there to be a customer_id field on the orders table.
If you have followed these conventions then rails will use them and will be able to build the necessary SQL to find all the orders for a given customer.
If you look at the development.log file when you are developing your application you will be able to see the necessary SQL being built to select all orders for a given customer.
Rails does not create tables without you asking it to. The creation of tables is achieved by generating a migration which will create/alter tables for you. The fact that you create a customer model and then state within it that it has_many :orders will not create you an orders table. You will need to do that for yourself within a migration to create an orders table. Within that migration you will need to either add a customer_id column or use the belongs_to: customer statement to get the customer_id field added to the orders table.
The rails guide for this is pretty useful

Resources