rubykatz
rubykatz

Reputation: 288

Rails: Store has many Images; best practice to define "main image"?

My models include Stores which have a number of Images. (There are other models that can have Images, too.) Out of all Images that are assigned to a Store, I would like to set a "main image" which will be presented first on the Store's page. Other than that the main image should be treated in the same way as all others.

What is the best practice?

The models basically look like this:

class Store < ActiveRecord::Base
  has_many :images, as: :imageable, dependent: :destroy
end

and

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

Upvotes: 1

Views: 321

Answers (2)

max
max

Reputation: 101811

Adding a foreign key reference to the stores table is not actually a bad idea.

Since polymorphic relationships are resolved in the software layer and not in the RBDMS there is nothing in the DB which maintains the referential integrity. The DB will for example happily let you delete the primary image for a store.

First lets generate a migration:

class AddPrimaryImageToStores < ActiveRecord::Migration[5.0]
  def change
    # we need to setup the foreign_key manually
    add_reference :stores, :primary_image, foreign_key: false
    add_foreign_key :stores, :images, column: 'primary_image_id'
  end
end

Then lets setup the relation:

class Store < ActiveRecord::Base
  has_many :images, as: :imageable, dependent: :destroy

  belongs_to :primary_image, class_name: 'Image'
end

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

  # one to one.
  has_one :primary_store, class_name: 'Store'
                          foreign_key: 'primary_image_id'

end

The direct relationship with a foreign key allows you to perform highly effective joins which is especially important if you are displaying stores and the primary image together.

Upvotes: 2

Andrey Saleba
Andrey Saleba

Reputation: 2197

You can add some boolean field to your image model to define if image is main, and add scope to your model to get this main image by that new boolean field

Upvotes: 0

Related Questions