Get products of children categories - ruby-on-rails

I have a model, called Groups, it's self-referential, there are groups in it - parents and children together, linked by parent_id. So I can get children of a group and products connected to one of groups, but how can I get all products of parent group through its children?
Here is my model:
class Group < ActiveRecord::Base
belongs_to :parent, class_name: 'Group', foreign_key: :parent_id
has_many :children, class_name: 'Group', foreign_key: :parent_id
has_many :products
validates :id, uniqueness: true
self.primary_key = :id
end
It would be great if, for example, I could call group.products and get all products, that are direct descendants of that group and all products of children groups.
It would be even better if I could paginate them with something like Kaminari(or another paginator).
P.S. I tried to insert someting like has_many :products, through: :children, but all I get is Stack level is too deep...
P.P.S. I can create method that will collect all products in Hash, but I won't be able to sort list of products by title, price etc.

Try this
class Group < ActiveRecord::Base
belongs_to :parent, class_name: 'Group', foreign_key: :parent_id
has_many :children, class_name: 'Group', foreign_key: :parent_id
has_many :products
has_many :child_products, :through => :children, :source => :products
validates :id, uniqueness: true
self.primary_key = :id
end

Related

Rails model has_many association to the same model

I have two models: Category and Subcategory
And I can have situation that Subcategory will include more Subcategories
How Can I do it with rails associations?
Now my code:
category.rb
class Category < ApplicationRecord
has_many :subcategories, :dependent => :destroy
end
subcategory.rb
class Subcategory < ApplicationRecord
belongs_to :category
has_many :products, :dependent => :destroy
end
Possible example:
Category Readable --> Subcategory Books --> Subcategory Books for kids --> products
This is a good case for a polymorphic belongs_to association.
#on Subcategory model
belongs_to :parent, polymorphic: true
has_many :subcategories, as: :parent, dependent: :destroy
#on Category model
has_many :subcategories, as: :parent, dependent: :destroy
#on the database
t.references :parent, polymorphic: true, index: true # this adds two columns, parent_id and parent_type
Now you can assign anything anything as the parent for a subcategory and you can call subcategory.parent to get either a Category or a Subcategory
https://guides.rubyonrails.org/association_basics.html#polymorphic-associations
You can try to add subcategory_id to your subcategory model by migration and add has_many :subcategories in your subcategory model.
Or you can add
belongs_to :parent, :class_name => "Subcategory", :foreign_key => "parent_subcategory_id"
has_many :child_subcategories, :class_name => "Subcategory", :foreign_key => "child_subcategory_id"

Act as list with self-referential association

I have a self-referential association for categories table:
class Category < ApplicationRecord
has_many :subcategories,
class_name: 'Category',
foreign_key: 'parent_id',
dependent: :destroy,
inverse_of: :parent
belongs_to :parent,
class_name: 'Category',
optional: true,
inverse_of: :subcategories
end
I wanted to add act_as_list gem to manage position of elements for main categories and subcategories in scope of main category. As I read documentation it seems that there is no possibility for such scenario. Is there any workaround?

Get data through many to many relations

I have 3 tables:
User class
User has_many :project_assignments
User has_many :projects, through: :project_assignments
ProjectAssignment class
ProjectAssignment belongs_to :user
ProjectAssignment belongs_to :project_owner, class_name: 'User', foreign_key: 'user_creator_id'
ProjectAssignment belongs_to :project
Project
has_many :project_assignments
has_many :users, through: :project_assignments
ProjectAssignment has the columns:
project_id, user_id, creator_user_id
I want to get all the projects, for a user through creator_user_id
ex: current_user.created_projects
The query: ProjectAssignment.where(creator_user_id: current_user.id)
Can it be done when defining the relations in the models, the same as I did with projects but the foreign_key should be creator_user_id
I think you just need another couple of associations in User which leverage the creator_user_id field (as opposed to user.projects which will return the projects the user is a member of)
Try this -
#in User class
has_many :owned_project_assignments, :class_name => "ProjectAssignment", :as => :project_owner, :foreign_key => "user_creator_id"
has_many :owned_projects, :through => owned_project_assignments, :class_name => "Project", :source => :project, :as => :project_owner
the :source and :as options can be a bit tricksy, so this might not work, it's just off the top of my head...
In my case this was the correct solution:
has_many :owned_project_assignments, class_name: "ProjectAssignment", foreign_key: 'user_creator_id'
has_many :owned_projects, through: :owned_project_assignments, source: :project

Ruby on Rails: filter associations based on several relations and conditions

In my application I the have the models Category, Item, Property and PropertyValuation. The idea is that a category contains items, and an item has several properties. PropertyValuation purpose is to store the property value for the specific items. The models are defined as above:
class Category < ActiveRecord::Base
attr_accessible :name, :description, :parent, :children, :items, :parent_id
has_many :children, :class_name => "Category", :foreign_key => "parent_id", :dependent => :nullify
belongs_to :parent, :class_name => "Category"
has_many :categorizations
has_many :items, :through => :categorizations
end
class Item < ActiveRecord::Base
attr_accessible :name, :description, :property_valuations, :barcode
has_many :property_valuations, :dependent => :destroy
has_many :properties, :through => :property_valuations
has_many :categorizations
has_many :categories, :through => :categorizations
end
class Property < ActiveRecord::Base
attr_accessible :name, :description, :value_type, :unit, :unit_id
has_many :property_valuations, :dependent => :destroy
has_many :items, :through => :property_valuations
has_many :property_ranges, :dependent => :destroy
belongs_to :unit
end
class PropertyValuation < ActiveRecord::Base
attr_accessible :property, :item, :value, :categorization
belongs_to :property
belongs_to :item
end
Now my question, I've successfully managed to filter categories items by name by doing this:
#category.items.where("lower(items.name) like ?", "%#{params[:keywords].downcase}%")
But now I also want to filter those items depending on the associated property value. I receive the property ids and the values for each property (exact value, minimum value or maximum value), and the idea is to build the query dynamically. Given my models, how can I do this for example: I want the items whose name contains "foo", and where property with id=1 has value 2, property with id=2 has value<10, and property with id=8 has value>2 and value<5.
You can drive the search off the PropertyValuation model and join it to the product and category models
valuations = PropertyValuation.joins(:item)
.where(value: 2, property_id: 1)
.where('lower(items.name) LIKE ?', "%#{params[keywords].downcase}%")
items = valuations.map(&:item)
There a gems that make this thing a long easier, one is Ransack https://github.com/ernie/ransack
Item.search(name_contains: params[:keywords],
product_valuations_value_equals: 2,
product_valuations_property_id: 1)

Rails scope checking for no associations

I have a Category model where a category may have some subcategories (category.categories). I want a scope that gives me all Categorys that have no subcategories.
In other words, I can write
without_subcategories = Category.select{|category| category.categories.none?}
but I would like to write this as a scope. How do I do this?
In case it's not clear, this is my model:
class Category < ActiveRecord::Base
belongs_to :parent, class_name: 'Category'
has_many :categories, foreign_key: :parent_id, class_name: 'Category'
scope :without_subcategories, lambda { WHAT GOES IN HERE? }
end
the best practice is minimize db queries by implementing a counter cache.
In rails this is super simple by adding an option :counter_cache => true to the belongs_to association. This assumes you create a 'categories_count' integer column in your categories db table. Given this, your scope is trivial.
class Category < ActiveRecord::Base
belongs_to :parent, class_name: 'Category', :counter_cache => true
has_many :categories, foreign_key: :parent_id, class_name: 'Category'
scope :without_subcategories, where(categories_count: 0)
end
hope this helped.

Resources