rails touch chain with has_many :through associations - ruby-on-rails-4

Using a join model, with a has_many :through on this example setup
class Collage
has_many :arrangements
has_many :photos, through: :arrangements
class Photo
has_many :arragements
has_many :collages, through: :arragements
end
class Arragement
belongs_to :photo
belongs_to _collage
end
The photo may change it size, which will cause the collage to change
Using the touch: true, doesn't work this way, because the chain isn't "one way up", as arragement points to Photo and Collage
How can I work this so a Photo change (ie touch) would also touch its Collages?

Here's an even shorter version:
class Photo
has_many :arragements
has_many :collages, through: :arragements
after_save { collages.find_each(&:touch) }
end

You could just manually touch them all.
class Photo
has_many :arragements
has_many :collages, through: :arragements
after_save do
collages.update_all updated_at: Time.now
end
end

Related

Rails includes with has_many through giving avoid eger loading n+1 by bullet gem

My Models are like:
class ThreeDModel < ApplicationRecord
has_many :three_d_model_animations
has_many :animations, through: :three_d_model_animations
has_many :three_d_model_images, dependent: :destroy
has_many :three_d_garments
has_one :model_efm
has_one :model_edm
end
2nd:
class ThreeDModelAnimation < ApplicationRecord
belongs_to :animation
belongs_to :three_d_model
validates_presence_of :animation_file
#validates_presence_of :motion
mount_uploader :animation_file, ThreeDModelAnimationUploader
enum animation_motions: {
'Run': 'run',
'Turn Aroun (100 Frames)': 'turn_around_100_frames',
'Turn Around (300 Frames)': 'turn_around_300_frames',
'Walk (58 Frames)': 'walk_58_frames',
'Walk (92 Frames)': 'walk_92_frames'
}
end
3rd:
class Animation < ApplicationRecord
has_many :three_d_model_animations
has_many :three_d_models, through: :three_d_model_animations
mount_uploader :video, AnimationVideoUploader
validates_presence_of :video
validates :name, :frames, :loop_start, :loop_end, presence: true
end
Now my query is:
#model = ThreeDModel.where(id: params[:id]).includes(:model_efm, :model_edm, :three_d_model_images, :three_d_model_animations, :animations).last
which gives the following message by the bullet gem:
AVOID eager loading detected
ThreeDModel => [:three_d_model_animations, :animations]
is there a better way so that n+1 could be avoided. Thanks in advance

Can a model have two associations to the same model, using :through?

Let's say I have three models: Organization, Skills and Assessments.
Can an Assessment belong to two different Organizations, via different relations?
For example, an assessment may have happened at organization A, but was based on a skill belonging to organization B.
Below are my models and associations:
class Organization < ActiveRecord::Base
has_many :checklists
has_many :levels, :through => :checklists
has_many :sections, :through => :levels
has_many :skills, :through => :sections
has_many :assessments_using_own_checklists, :through => :skills, :source => :assessments
end
class Skill < ActiveRecord::Base
belongs_to :section
has_one :level, through: :section
has_one :checklist, through: :level
has_one :organization, through: :checklist
has_many :assessments
end
class Assessment < ActiveRecord::Base
belongs_to :skill
has_one :section, through: :skill
has_one :level, through: :section
has_one :checklist, through: :level
has_one :checklist_owner, through: :checklist, source: :organization
belongs_to :organization
end
Using the above, I can get an assessment's organization:
Assessment.last.organization # yields organization 1
I can also get an assessment's checklist_owner:
Assessment.last.checklist_owner # yields organization 2
But when I try to use checklist_owner in a where, the association seems to forget to use the :through. For example, if I run:
Assessment.where(organization: Organization.find(2), checklist_owner: Organization.find(1))
... this translates to SQL:
SELECT "assessments".* FROM "assessments" WHERE "assessments"."organization_id" = 2 AND "assessments"."organization_id" = 1
See how the SQL has two "assessments"."organization_id" = statements? Why does it do that?
Have you tried using joins?
something like:
Assessment.joins(skill: { section: { level: :checklist } }).where(organization: Organization.find(2), checklists: { organization_id: Organization.find(1) })
I know it look bad, but it seems that your relation from assessment to checklist is very complicated. This would take care of any weird relations being made.

Rails 4: how to use form_for (has_many :through with extra attributes)

I have a Store model, Product model, and a StoreProduct model to form a many-to-many relationship between stores and products.
The StoreProduct model, on top of store_id and product_id, has an attribute price:float.
I'm struggling to figure out how I can design a form to create a new product given the store. Is it better off making a form for a new StoreProduct object? What is the conventional way of doing this?
store.rb
class Store < ActiveRecord::Base
validates :name, presence: true
has_many :store_products
has_many :products, through: :store_products
end
product.rb
class Product < ActiveRecord::Base
validates :name, presence: true
validates_numericality_of :price, on: :create
has_many :reviews
has_many :users, through: :reviews
has_many :store_products
has_many :stores, through: :store_products
end
store_product.rb
class StoreProduct < ActiveRecord::Base
belongs_to :store
belongs_to :product
end

How to do a Polymorphic model association with another model

I have two basic models:
class Case < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :case
belongs_to :contactable, :polymorphic => true, :foreign_key => :contactable_id
end
I also have quite a few models that are "sub types" of the Contact model:
class Attorney < ActiveRecord::Base
has_one :contact, as: :contactable, dependent: :destroy
accepts_nested_attributes_for :contact
end
class Client < ActiveRecord::Base
has_one :contact, as: :contactable, dependent: :destroy
accepts_nested_attributes_for :contact
end
I used polymorphic associations instead of STI because I don't want one table to store all the fields, which can get a little slow and overwhelming.
I am wondering if the has_many :contacts line from the Case model is correct. I try to use it in my console, but it doesn't really work the way I expected. Am I missing something?
I basically want an association where a Case can have many Contacts and a contact can belong to many cases. The contact can be of any type (Attorney or Client or Contact by itself). I was hoping it was as easy as case has_many :contacts

rails scope through has_many association

I have two models for Show and Performance (show as in a play or comedy show). They are associated like this in the models:
class Show < ActiveRecord::Base
has_many :performances, :dependent => :destroy
accepts_nested_attributes_for :performances
end
class Performance < ActiveRecord::Base
belongs_to :show
end
In the Performance model there is a datetime called :start_time.
How do I define a scope in the model which returns all Shows with at least one performance whose :start_time is in the future?
Also, how do I define a scope that returns all Shows that do not have any performances in whose :start_time is in the future?
class Show < ActiveRecord::Base
has_many :performances, :dependent => :destroy
accepts_nested_attributes_for :performances
scope :shows_with_pending_performance, includes(:performances).where("performances.start_time >= ? ", Date.today)
end
class Performance < ActiveRecord::Base
belongs_to :show
end