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"
Related
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?
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
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)
In my app I have 3 models: Item, Category and Categorization defined as below:
class Item < ActiveRecord::Base
attr_accessible :name, :description
has_many :categorizations
has_many :categories, :through => :categorizations
end
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 Categorization < ActiveRecord::Base
attr_accessible :category, :item
belongs_to :category
belongs_to :item
end
However, doing this:
Category.where(:parent_id => self.id).includes(:items)
won't return me the items associated to the category. What am I missing here?
Try this:
Category.where(parent_id: id).joins(:items)
Try this:
Category.where(:parent_id => id).collect(&:items)
It will return the items of all categories matching the where clause.
I have item, region and category table they are join through item_region ans item_category table their relationship is as follow
class Item < ActiveRecord::Base
has_many :item_region
has_many :region, :through => :item_region
has_many :item_category
has_many :category, :through => :item_category
class Region < ActiveRecord::Base
has_many :category
has_many :item, ::through => :item_category
class ItemRegion < ActiveRecord::Base
belongs_to :item
belongs_to :region
end
class Category < ActiveRecord::Base
has_many :item, :through => :item_category
has_many :item_category
class ItemCategory < ActiveRecord::Base
belongs_to :item
belongs_to :category
end
I want to find all fields of item and category_name and region_name from region_id,category_id and item_id using join table.
Thanks.
I hope I got this one correct. What about obtaining the required item, then the desired region and category from it.
item = Item.find(item_id)
region = item.regions.where(:id => region_id)
category = item.categories.where(:id => category_id)
Another suggestion, you are better off providing plural form for your associations. Its intuitive to do object.collections for a has_many association. Note that Rails will still function with above code but that doesn't follow CoC(convention over configuration) principle of Rails. If you follow the convention, you wouldn't have to do a lot of configurations.
Check the examples here http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
Personally, I'd prefer to have my associations in Item model as :
class Item < ActiveRecord::Base
has_many :item_regions
has_many :regions, :through => :item_regions
has_many :item_categories
has_many :categories, :through => :item_categories