Вопрос

I'm trying to get three polymorphic associations working from my Booth model with below

has_one :uploaded_file, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :uploaded_file

has_one :company_logo, as: :imageable, class_name: 'UploadedFile', dependent: :destroy
accepts_nested_attributes_for :company_logo

has_one :booth_main_image, as: :imageable, class_name: 'UploadedFile', dependent: :destroy
accepts_nested_attributes_for :booth_main_image

This however does not work and I'm getting same values in the view when I use build method on the resource for that association separately.

In my uploaded_files table in the database I have imageable_id and imageable_type I want to reuse this for things like company logo and booth main image because otherwise I have to create more columns to support other polymorphic associations and they will be left with null if not used.

Below is my model for UploadedFile:

class UploadedFile < ActiveRecord::Base
    belongs_to :imageable, polymorphic: true

    has_attached_file :assets

    validates_attachment_content_type :assets, 
        :content_type => /^image\/(png|gif|jpeg)/,
        :default_url => "/images/:style/missing.png",
        :message => "only (png|gif|jpeg) images are allowed and the size cannot exceed 5mb",
        :size => { :in => 0..5000.kilobytes }

end

Is there a way to utilise one set of polymorphic columns for all of the above associations?

Это было полезно?

Решение

The reason you are having this problem is because has_one will ensure that only one record in the target table (uploaded_files in your case), will point back to the Booth model. If you want to differentiate between different types of the same model, you'll need to set a flag somewhere that indicates which type it is.

To do this, first you'll need to add a column that identifies the image type:

# in a migration
def change
  add_column :uploaded_files, :image_type, :string
end

You can define the expected image types as constants:

class UploadedFile < ActiveRecord::Base
  IMAGE_TYPE_STANDARD = 'Standard'
  IMAGE_TYPE_LOGO     = 'Logo'
  IMAGE_TYPE_BOOTH    = 'Booth'
end

Now your associations should reflect these types:

class Booth < ActiveRecord::Base
  # optional - if you want to access all attached uploads
  has_many :uploaded_files, :as => :imageable, :dependent => :destroy

  has_one  :uploaded_file, :as => :imageable, :dependent => :destroy, 
           conditions: { image_type: UploadedFile::IMAGE_TYPE_STANDARD }
  has_one  :company_logo, :as => :imageable, :class_name => 'UploadedFile', 
           :dependent => :destroy, 
           conditions: { image_type: UploadedFile::IMAGE_TYPE_LOGO }
  has_one  :booth_main_image, :as => :imageable, :class_name => 'UploadedFile', 
           :dependent => :destroy, 
           conditions: { image_type: UploadedFile::IMAGE_TYPE_BOOTH }

  accepts_nested_attributes_for ...
end

Note that you won't have to set the image_type manually. Since the type is set by the condition, ActiveRecord will set it for you when you build or create off one of the has_one associations:

upload = @booth.build_uploaded_file(asset: some_asset)
upload.image_type 
=> 'Standard'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top