TimPetricola
TimPetricola

Reputation: 1491

Multiple polymorphic association on a same model in rails

I have a polymorphic association on an Image model and need to have two associations on it from a Place model. Something like:

class Place < ActiveRecord::Base
  has_many :pictures, as: :imageable, class_name: 'Image'
  has_one :cover_image, as: :imageable, class_name: 'Image'
end

class Image < ActiveRecord::Base
  belongs_to :imageable, polymorphic: true
end

This obviously doesn't work has the Image model doesn't know the difference between pictures and cover_image and every image is stored with

#<Image ... imageable_id: 17, imageable_type: "Place">

I was thinking about adding a imageable_sub_type column to Image to store a subtype.. So my images would look like:

#<Image ... imageable_id: 17, imageable_type: "Place", imageable_sub_type: "cover_image">

I can easily retrieve only the images with that subtype from my association in Place:

has_one :cover_image, -> { where(imageable_sub_type: 'cover_image'), as: :imageable, class_name: 'Image'

But I don't find a way to set this value while adding an image to a Place (actually it is always set to nil).

Is there a way to do that?


I tried to do it this way: https://stackoverflow.com/a/3078286/1015177 but the problem remains the same, the imageable_sub_type remains nil.

Upvotes: 2

Views: 2317

Answers (2)

tihom
tihom

Reputation: 8003

by adding the condition in the relation, it is letting you retrieve the images with imageable_sub_type = cover_image when you call place.cover_image. It will not set the attribute for you when you add the image. That has to be done separately when the image is added based on some input from the view like a checkbox tag.

Update: You can override the default association= method , sthing like below in Place model:

 def cover_image=(img)
     # add the img to tthe associated pictures 
     self.pictures << img 

     # mark current img type as cover
     img.update_attribute(:imageable_sub_type, "cover_image")

     # mark all other images type as nil, this to avoid multiple cover images, 
     Picture.update_all( {:imageable_sub_type => nil}, {:id => (self.pictures-[img])} ) 

 end

Upvotes: 0

Lachlan
Lachlan

Reputation: 11

When using a condition on a relation, it will assign that condition if you build the record through the relation (ie using create_cover_image).

If you want it to change the value of imageable_sub_type when assigning an exiting instance of Image, then you could overwrite cover_image= to do that. ie

def cover_image= cover_image
  cover_image.imageable_sub_type = 'cover_image'
  super
end

Upvotes: 1

Related Questions