I have a list of products and a list of categories. Also I have a mapping table product_categories which tells that products come under different categories and also category has many products. Here the category list is defined by admin. The number of categories is fixed, but can be varied. Now I need to get the list of products which are mapped with categories
product.rb
has_many :product_categories, dependent: :destroy
has_many :categories, through: :product_categories
category.rb
has_many :product_categories
has_many :products, :through => :product_categories
product_category.rb
belongs_to :product
belongs_to :category
I have written the code as:
ProductCategory.joins(:category).map(&:category).uniq
Is there any way to simplify this line?
To get a list of categories that have products you can use SQL inner join, which is the default in rails.
Category.joins(:product_categories).distinct
Try this,
Category.joins(:products).distinct
Related
I have the following relations:
reservation.rb
has_many :room_requests, dependent: :destroy, inverse_of: :reservation
accepts_nested_attributes_for :room_requests, allow_destroy: true
has_many :rooms, through: :room_requests
room_request.rb
belongs_to :reservation
belongs_to :room
room.rb
has_many :room_requests
has_many :reservations, through: :room_requests
And I'm trying update the attribute 'status' from rooms that belong to certain reservations. Something like:
Reservation.joins(:rooms).update_all('rooms.status': 'to_clean')
But evidently it doesn't work like this. I want to do it in a single query but I can't quite grasp it. What am I missing?
In the end I couldn't do the query that way because what I needed to update was on the Room model, and the query was being done in the Reservation model. I needed to reverse it, and came up with this:
Room.where(id: RoomRequest.where(reservation: Reservation.checked_in).select(:room_id)).update_all(status: Room.statuses[:to_clean])
You should link your Reservations model also with Rooms via a has_many, through: room_requests..
Once done you can easily go with:
Reservations.rooms.status.update_all('rooms.status': 'to_clean')
However, make sure that your room_requests are available and that reservations are thus assigned to rooms via the room_requests.
Cheers,
T
category.rb
has_many :topics
topic.rb
belongs_to :category
has_many :answers
answer.rb
belongs_to :topic
Question:
How can i preform queries like Category.first.topics.answers.count
Use a has_many :through relation:
# Category.rb
has_many :topics
has_many :answers, through: :topics
Now you can access all answers from all topics like so:
Category.first.answers.count
if you are set on your schema configuration (i.e. not using a has_many :through), you'd want to start with Answers and utilize a couple of joins to get to Category
Answers.joins(topic: :category).where(categories: { id: category_id })
here we're joining on a nested association, and then using a where clause to filter out by the category_id
note: i think this is the right syntax, but you may need to fiddle around with the plurality of topic and category there
I have two models: Orders and Items. This is a many to many relationship, but I'm unsure if HMT is correct
Order model:
-user_id
-transaction_cost
-delivery_time
Item model:
-price
-name
Orders should be able to get all items in the order
Items do not need to be able to get all orders
The convention on this is to use the names of both models. A good name might be ItemOrders. Has many through is almost certainly a correct choice here.
class Order < ActiveRecord::Base
has_many :item_orders, dependent: :destroy
has_many :items, through: :item_orders
end
class Item < ActiveRecord::Base
has_many :item_orders, dependent: :destroy
has_many :orders, through: :item_orders
end
class ItemOrder < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
Now you just have another ActiveRecord model, and you can add to it as you'd like. It will also be helpful for debugging. You can even use a model/scaffold generator to generate these:
rails g model item_order order:references item:references
This way you get the migrations correct right away. Nothing needs to be altered on your other models except for the above code.
I have created a has_many relationship where a Food can be served at several different kinds of meals.
For instance, eggs can be served at a user's breakfast or brunch.
That is, a Food is allowed to be served only at certain meals and this is tracked with a has_many relationship named meal_type.
Now suppose I have filtered my initial table by a certain query, such as:
#hot_foods = Foods.where(:is_hot => 1).
And now I want to find out of the hot foods, only those that can be served at lunch.
Specifically, the relationships are given as follows:
class Food
has_many :meals, :through => :relationships
has_many :relationships
class Meal
has_many :foods, :through => :relationships
has_many :relationships
class Relationships
belongs_to :food
belongs_to :meals
How would I perform this query?
To make the query easier, start with the Meal and work backwards:
#meal = Meal.find_by_name('Lunch')
#meal.foods.where('foods.is_hot' => true)
Having properly defined has_many ..., :through relationships allows you do to this in a pretty straight-forward way.
I'm writing some tricky polymorphic relationships to handle tagging.
I have a Tag model, and a Tagging model which belongs_to a polymorphic taggable.
I have an Item model, which has_many :taggings, :as => :taggable, and has_many :tags, :through => :taggings, so that I can call #item.tags.
This is all working ok.
I want to bring another model into the mix - a Store which has_many :items. I want to be able to find all tags associated with all items in the store using #store.tags.
Here's what I have:
class Store < AR::Base
has_many :items
has_many :tags, :through => :items, :source => :taggings
However, this returns all of the taggings associated with items in the store, not the actual tags.
How do I get specify that the store has_many tags, through items, through taggings?
Can post more info if needed - trying to prevent information overload! Thanks :)
The source for a has_many association must be a belongs_to, has_one, or has_many association without a :through option (thanks to this answer for info).
There is a plugin that some people have had success with, but in my case it didn't seem to work correctly with my taggable polymorphic association.
At the moment, my solution is to pass a finder_sql option to has_many:
class Store < ActiveRecord::Base
has_many :items
has_many :tags, :finder_sql =>
'SELECT tags.* from tags
INNER JOIN taggings on tags.id = taggings.tag_id
INNER JOIN items on items.id = taggings.taggable_id AND taggings.taggable_type = "Item"
WHERE items.store_id = #{id}'
end
You can do in plain Ruby:
site.wares.map(&:tags).flatten.uniq
This will be inefficient though, unless you have a low number of tags / wares / items.