Rails has_many through with where clause - ruby-on-rails

I need help to achieve something.
Is it possible that my Analysis has_many :klasses, through: :subjects, but filtered using attributes from the join table AnalysisSubject? Or my models should be different?
class Analysis
has_many :analysis_subjects, dependent: :destroy
has_many :subjects, through: :analysis_subjects
has_many :klasses, -> { where(year: ??????, semester: ??????), through: :subjects
end
class AnalysisSubject
belongs_to :analysis
belongs_to :subject
# There are year:integer and semester:integer attributes
# I want to use those attributes in my where clause for analysis.klasses
end
class Subject
has_many :klasses
has_many :analysis_subjects
has_many :analyses, through: :analysis_subjects
end
class Klass
belongs_to :subject
end
I'm using Rails 5 if it is important. Thank you for your help.

Yes, but you should afford it in a different way: You must declare the where in a has_many :filtered_analysis_subjects.
class Analysis
has_many :filtered_analisys_subjects, -> { where(year: x, semester: y }, foreign_key: "analysis_id", class_name: "AnalysisSubject", dependent: :destroy
has_many :subjects, through: :filtered_analysis_subjects
has_many :klasses, through: :subjects

Related

Rails ActiveRecord joins with multiple tables

I have a Category Model which belongs to Offer Model through a third Model OfferCategory. I also have a similar association for PlumCake Model which is associated to Category model through PlumCakeCategory Model.
Category:
has_many :offer_categories, dependent: :destroy, inverse_of: :category
has_many :offers, through: :offer_categories, source: :offer
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :category
has_many :plum_cakes, through: :plum_cake_categories, source: :plum_cake
Offer:
has_many :offer_categories, dependent: :destroy, inverse_of: :offer
has_many :categories, through: :offer_categories, source: :category, dependent: :destroy
OfferCategory:
belongs_to :offer
belongs_to :category
PlumCake:
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :plum_cake
has_many :categories, through: :plum_cake_categories, source: :category, dependent: :destroy
PlumCakeCategory:
belongs_to :plum_cake
belongs_to :category
and a similar association for category/plumcakes as well.
Now I want to get all categoires that the selected offers and plumcakes has. The following query gives me the list of categories that the eligible_offer_ids offers has.
Category.joins(:offer_categories).where(offer_categories: { offer_id: eligible_offer_ids })
I can fire a similar query for plum_cake and get uniq categoires of these two queries.
cat1 = Category.joins(:offer_categories).where(offer_categories: { offer_id: eligible_offer_ids })
cat2 = Category.joins(:plum_cake_categories).where(plum_cake_categories: { plum_cake_id: eligible_plum_cake_ids })
(cat1 + cat2).uniq
But Is there a way I get the same result((cat1 + cat2).uniq) in a single query?
if you don't to want change your structure:
Category.left_outer_joins(:offer_categories, :plum_cake_categories).where(offer_categories: { offer_id: eligible_offer_ids }).or(Category.left_outer_joins(:offer_categories, :plum_cake_categories).where(plum_cake_categories: { plum_cake_id: eligible_plum_cake_ids })).uniq
I think if you use rails STI(single table inheritance) you can easily implement your functionality.
if your structure be somthing like following:
class Category
has_many :offer_categories, dependent: :destroy, inverse_of: :category
has_many :offers, through: :offer_categories, source: :offer
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :category
has_many :plum_cakes, through: :plum_cake_categories, source: :plum_cake
has_many :sub_categories
end
class SubCategory
belongs_to :offer
belongs_to :plum_cake
belongs_to :category
end
class OfferCategory < SubCategory
validate_presence_of :offer_id
end
class PlumCakeCategory < SubCategory
validate_presence_of :plum_cake_id
end
your query will be:
Category.joins(:sub_categories).where(sub_categories: { offer_id: eligible_offer_ids }).or(Category.joins(:sub_categories).where(sub_categories: { plum_cake_id: eligible_plum_cake_ids }))
STI documentation

Rails AMS, specify different serializers in polymorphic list

I implemented a multi-table search using pg_search, and then serialize the result with Active Model Serializer (version 0.10) - it works fine, but AMS uses the default serializer for each of the types returned.
Here's the serializer:
class SearchBarSerializer < ApplicationSerializer
attributes :searchable_type
belongs_to :searchable
end
Thus, for example, when serializing the returned objects from pg_search, if the relevant object is a "User", then AMS uses UserSerializer. If the relevant type is a league, then AMS uses LeagueSerializer.
That's fine - but I would like to use a different serializer for each type. This is for a search bar, and so I only care about a much smaller amount of data than the full standard serializer. (EDIT: the standard serializers serialize all attributes and associations for each of the User and League models, which can be seen below. Each model is somewhat significantly large, and for the purposes of just a search, I really only need each model's name and id, and perhaps some other smaller data for each type)
Is there some way that I can specify which serializer to use depending on the object?
Thank you!
EDIT:
User Model:
class User < ActiveRecord::Base
include PgSearch
#################### Associations
has_and_belongs_to_many :roles
belongs_to :profile_page_visibility, optional: true # the optional part is just for when user's are created.
has_and_belongs_to_many :leagues, class_name: "Leagues::League", join_table: "users_leagues_leagues"
has_one :customer, class_name: "Payments::Customer", dependent: :destroy
has_many :unpaid_charges, class_name: "Payments::UnpaidCharge", dependent: :destroy
has_many :charges, class_name: "Payments::Charge", dependent: :destroy
has_many :cards, class_name: "Payments::Card", dependent: :destroy
has_many :league_join_requests, class_name: "Leagues::JoinRequest", dependent: :destroy
has_many :notifications, class_name: "Notification", foreign_key: :recipient_id
has_many :league_invitations, class_name: "Leagues::Invitation", dependent: :destroy
has_many :teams, class_name: "Leagues::Team"
has_many :divisions, class_name: "Leagues::Division" # Can act as division commissioner
has_many :conferences, class_name: "Leagues::Conference" # Can act as conference commissioner
League Model:
class Leagues::League < ApplicationRecord
enum pay_level: [ :basic, :custom, :premium ]
include PgSearch
#################### Associations
has_and_belongs_to_many :users, class_name: "User", join_table: "users_leagues_leagues"
has_and_belongs_to_many :commissioners, class_name: "User", join_table: "commissioners_leagues_leagues"
belongs_to :commissioner, class_name: "User", foreign_key: :commissioner_id, optional: true
has_and_belongs_to_many :feature_requests, class_name: "FeatureRequest", join_table: "feature_requests_leagues_leagues"
has_many :join_requests, class_name: "Leagues::JoinRequest", dependent: :destroy
has_many :invitations, class_name: "Leagues::Invitation", dependent: :destroy
has_many :notifications, class_name: "Notification", as: :notifiable_subject, dependent: :destroy
has_many :teams, class_name: "Leagues::Team", dependent: :destroy
has_many :conferences, class_name: "Leagues::Conference", dependent: :destroy
has_many :divisions, class_name: "Leagues::Division", dependent: :destroy
If you want to define a specific serializer lookup for your associations, you can override the ActiveModel::Serializer.serializer_for method to return a serializer class based on defined conditions.
For your case, it might look something like:
class SearchBarSerializer < ApplicationSerializer
attributes :searchable_type
belongs_to :searchable
class << self
def serializer_for(model, options)
return TinyUserSerializer if model.class == User
return TinyLeagueSerializer if model.class == Leagues::League
super
end
end
end

Remove association from Rails 5 self join table without deleting

I have a self join table on my product model using a model called matches as the join table. What I would like to do is when deleting a product to have the associated product removed but not deleted. Right now I am trying dependent: :destroy which doesn't work, but I know its not what I want because I don't want to delete the self associated product.
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches
has_many :matched_products, through: :matches, dependent: :destroy
...
end
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product', dependent: :destroy
has_many :variations, :through => :matched_product
end
I suggest you update your models as follows:
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches, dependent: :destroy
has_many :product_matches, class_name: 'Match', foreign_key: :matched_product_id, dependent: :destroy
has_many :matched_products, through: :matches
...
end
This will ensure that all matches records are deleted when deleting a product whether the product is a product or matched_product in the match record. Removing dependent: :destroy from has_many :matched_products will prevent deletion of the, well, matched_products.
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product'
has_many :variations, :through => :matched_product
end
Similar to above, removing dependent: :destroy from belongs_to :matched_product, class_name: 'Product' will prevent deletion of the matched_product.

Ransack: Search has_many through association

I am a newbie in Rails and have issues with Ransack:
This is model Project
class Project < ApplicationRecord
searchkick
belongs_to :company
belongs_to :m_category
has_many :project_industries, dependent: :destroy
has_many :m_industries, through: :project_industries
end
This is model Industry:
class Industry < ApplicationRecord
include M
belongs_to :m_industry_category
has_many :project_industries, dependent: :destroy, foreign_key: :industry_id
has_many :projects, through: :project_industries
end
And this is model IndustryCategory:
class IndustryCategory < ApplicationRecord
has_many :industries, dependent: :destroy,
foreign_key: :industry_category_id
has_many :projects, through: :industries
end
Now, I want to search the Project by IndustryCategory but I don't know how. please help me!! tks
You can use something like this
#industrty_category = IndustryCategory.find(params[:id])
#project = #industry_category.projects.all

Association from promotion rule to product not working

I'm trying to access products through promotion but can't.
In the command line: Promotion.last.promotion_rules.first.products
Returns an error of an uninitialized constant.
Here are my associations:
class Product
has_many :product_promotion_rules, class_name: 'ProductPromotionRule'
has_many :promotion_rules, through: :product_promotion_rules
end
class ProductPromotionRule
belongs_to :product
belongs_to :promotion_rule
end
class PromotionRule
has_many :product_promotion_rules, class_name: 'ProductPromotionRule', join_table: 'products_promotion_rules', foreign_key: :promotion_rule_id
has_many :products, through: :product_promotion_rules
belongs_to :promotion
end
class Promotion
has_many :promotion_rules
end
Within the Product model try:
has_many :product_promotion_rules, class_name: 'ProductPromotionRule', foreign_key: :product_id
has_many :promotion_rules, through: :product_promotion_rules, source: :promotion_rule
And within the PromotionRule model:
has_many :products, through: :product_promotion_rules, source: :product
Update: saw this, which you may want to remove/fix:
join_table: products_promotion_rules
Either change to:
join_table: product_promotion_rules
Or try removing it.

Resources