Rails HABTM: Select everything a that a record 'has' - ruby-on-rails

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!

Related

Filtering by ID and count with Rails AR

I have a many to many relation between users and teams, which is reflected in my rails models as has_many through (instead of HABTM) in both models.
I want to find all teams that contain the user with ID 42 and no other users. This would be quite easy in plain SQL, but I'm not sure how would that look using Rails AR.
My models are User, Team and Usersteam.
Unless you want to write complicated raw SQL, it'll be best to split this into two queries:
# assuming Team.table_name == 'teams'
user = User.find(42)
required_teams = user.teams.joins(:users).group('teams.id').having('COUNT(*) = 1')
This might solve your problem. It mixes some SQL fragments, but I don't know if this is doable in pure ActiveRecord. Possibly if you mix in Arel, but that would probably get even more messy.
Team.
joins(:usersteams, :users).
where(usersteams: { user_id: 42}).
having("count(usersteams.user_id) = 1").
group("teams.id, usersteams.user_id").
all

Tables for orders

I'm having a very difficult time setting up model/table relationships for a hobby project I'm working on. What I have is an order, the order will have one or many packages, each package has one or many products, each product will have one area it is assigned to. There can be multiple of the same product on the order and in the same package but each will have a different area
and a different quantity. I'm struggling to determine how the relationships are set up.
At the end of the day I need to run a report that shows me the order details listing all packages on the order and all the products and areas contained in each package. I also need a report that shows me the order and a sum of all the quantities for each product on the order (no packages on this one). I'm using Rails ActiveRecord I think believe there will be a couple polymorphic relationships, but I'm struggling to identify them as this is outside of my simple "everything has a one-to-many relationship" thinking.
How can I put these tables together in an intelligent manner? I have searched for similar schema diagrams without much success.
This is the basics of what I am thinking of for relationships, but I'm not sure what the Rails models will look like. It seems like every relationship from orders down is polymorphic; how do I nest these relationships in Rails?
I think you need some JOIN tables.
An Order can have many Products; a Product can be added to many Orders.
In that case you'd have a JOIN table that would have two columns: primary keys for Order and Product. The two together would be a composite primary key.
I don't know what Area means in your schema, but perhaps this suggestion will break the mental logjam for you.

ActiveRecord Associations should i be using 3 join tables?

i currently have 3 tables and 3 join tables
Users
Projects
Materials
a User has many Projects and Materials
a Project has many Users and Materials
a Material has many Projects and Users
each of them have their respective join tables to one another
say a Material has a column "name" and "amount". How can i form the associations so that for the same instance of materials, it has a different amount for a Project and a User?
I am currently storing "amount" in their join tables so a UserMaterial and a ProjectMaterial has different "amounts". The issue with that is when i query the materials from a User, I would have to make 2 separate queries. One to get an array of the Material names from the Materials table,
user.materials
and another to get an array of the amounts from the UserMaterial.
user.usermaterials
Is there an issue/improvement with my associations? or is there a query method to combine those 2 arrays, attaching the correct name and amount to the correct id?
Any assistance is appreciated. Thank you
If you query on user.materials, that will have to join through user_materials. If you use includes, it can get both in one query.
user_materials = #user.user_materials.includes(:material)
Then, when you loop through, the user_material.material association will already be loaded and ready for you.
user_materials.each do |um|
name = um.material.name # material is already loaded
end

Rails 4: how does rails handle join tables in "has_many through" relationships

I am new to rails. I'm trying to understand relationships in the database. I have 2 tables, users and disciplines and a join table called interests. Users have many disciplines through interests and disciplines have many users through interests.
But what if I want to update a users interests? Do I have to delete all entries directly in the join table and then create a new 'set' or is there a clever rails way that handles this where I can work directly on the outside models, users and disciplines.
I've looked for a direct answer to this for rails 4 without success.
Many thanks

Best way to recommend Products to Users based on Interest?

Let's say that each Product has a category. I want to ask the Users to select several categories that the user is interested in, and find the Products that have the same category. This is similar to what Quora, Stumbleupon, and Pinterest all do.
What would be the best way to set this database structure in Rails? Should I create 3 tables: User, Product, and Category, and make the relations
User has many Categories & Product has many Categories?
The problem I see with this is doesn't it create, rather than reference, a new instance of Categories to each row of Users and Products?
*extra: What if I wanted subcategories? For example, if the user chose Technology, it could further ask to choose between web dev, mobile dev, hardware, etc.
You could do that kind of 'recommendation' pretty easily.
Something like this should work (N.B.: I did not test this code, but it is right in spirit):
def recommended_products
joins(:categories, :products).where("product_id not in (?)", self.products)
end
Explanation of each bit:
joins(:categories, :products): this does a SQL join of users, products, and categories. This gives you a 'table' where each user-product-category combination is in it's own row.
.where("product_id not in (?)", self.products): adds a SQL where clause to filter out all the rows that have products in the current user's list of products.
The associations are not a problem. They don't create any new instances by themselves, only if you write code that creates new instances yourself.
As for sub categories, I think you'll do better to make that it's own question, as it's easily a whole post in itself.

Resources