Preload Has_Many Associations with Dynamic Conditions

Preload has_many associations with dynamic conditions

This seems to be the only solution that works:

# 1st query: load places
places = Place.all.to_a

# 2nd query: load events for given places, matching the date condition
events = Event.where(place: places.map(&:id)).where("start_date > '#{time_in_the_future}'")
events_by_place_id = events.group_by(&:place_id)

# 3: manually set the association
places.each do |place|
events = events_by_place_id[place.id] || []

association = place.association(:events)
association.loaded!
association.target.concat(events)
events.each { |event| association.set_inverse_instance(event) }
end

It's a bit hacky but it's quite easy to adapt to any situation where you might want to load an association using a separate query and then attach it to an existing object.

All credit goes to https://mrbrdo.wordpress.com/2013/09/25/manually-preloading-associations-in-rails-using-custom-scopessql/

Rails has_many with dynamic conditions


Rails 4+ way (Thanks to Thomas who answered this below):

has_many :faixas_aliquotas, -> (object) { 
where("regra_fiscal = ?", object.regra_fiscal)
},
:class_name => 'Fiscal::FaixaAliquota'

Rails 3.1+ way:

has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
:conditions => proc { "regra_fiscal = #{self.regra_fiscal}" }

Rails 3 and below:

has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
:conditions => ['regra_fiscal = #{self.regra_fiscal}']

No. This is not a mistake. The conditions are specified in single quotes and still contains the code #{self.regra_fiscal}. When the conditions clause is evaulated, the regra_fiscal method will be called on the object of self (whatever the class is). Putting double quotes will not work.

I hope this is what you are looking for.

Preload associations of an already loaded model

using model_instance.associated_model will only load the association for the first time.

If we open rails console and try it there, we'll see that it has queried the database only first time and after that all the calls to associated model didn't load it from database.

how can i specify dynamic conditions in has_many associations

You cannot use dynamic conditions in has_many. However, in your particular case it seems you need primary_key and foreign_key instead:

class Message  
has_many :threads, :class_name=>"Message", :primary_key => 'conversation_id', :foreign_key => 'conversation_id'
end

You may also be interested by one of the gems that adds tree structure to ActiveRecord.

How to preload child conditionally based on parent column?

You can use Custom Preloading SQL in Gorm

Example: Preload guests order by name desc.

    db.Where("code = ?", orderCode).Preload("Guests", func(db *gorm.DB) *gorm.DB {
return db.Order("guests.name DESC")
}).Find(&orders)
//// SELECT * FROM orders WHERE orders.code = "ABC";
//// SELECT * FROM guests WHERE order_id IN (1,2,3,4) order by guests.name DESC;

For working with parent-child condition you can use JOIN

db.Joins("JOIN orders ON orders.id = guests.order_id ").Find(&guests)

Combining both may work. Like

    db.Where("code = ?", orderCode).Preload("Guests", func(db *gorm.DB) *gorm.DB {
return db.Joins("JOIN orders ON orders.some_column_in_order_tbl = guests.some_column_in_guest_tbl")
}).Find(&orders)

Active Record: Eager load association with parameter

Step 1

Make the current_user accessible in the model layer (one technique is outlined here: https://stackoverflow.com/a/2513456/163203)

Step 2

Add an association with a condition that gets evaluated during run time.

Rails 2

class Item < ActiveRecord::Base
has_many :ratings
has_many :current_user_ratings,
:class_name => "Rating",
:conditions => 'ratings.user_id = #{User.current_user.try(:id)}'
end

Rails 3.1 and above

class Item < ActiveRecord::Base
has_many :ratings
has_many :current_user_ratings,
:class_name => "Rating",
:conditions => proc { ["ratings.user_id = ?", User.current_user.try(:id)] }
end

Step 3

Item.includes(:current_user_ratings)


Related Topics



Leave a reply



Submit