Ecto: multiple associations to one table?

Hello!

In my database, I am tracking articles and images. Every article has three images with predefined sizes. In pure SQL, table ‘articles’ would have three foreign keys: ‘big_image_id’, ‘medium_image_id’, and ‘small_image_id’.

Is there a way of achieving this with Ecto? I am trying it with belongs_to, has_one and foreign_key, but I get “field/association is already set on schema”.

I know that I could use has_many and use an intermediate table, but I don’t need this complication.

Thanks in advance,
Michal

You’ll want to use belongs_to in the articles table and has_one in the images table. The relationship setup you’re describing should work fine, so it’s likely an issue with the actual code. Want to share that?

Maybe relation like these…

belongs_to :big_image, Image, foreign_key: :big_image_id
belongs_to :medium_image, Image, foreign_key: :medium_image_id
belongs_to :small_image, Image, foreign_key: :small_image_id

But reverse association is clearly hard. An image has what? One big article? many articles? one big, one medium, one small articles? It’s hard to tell.

It’s really strange to link articles and images like this.

Another way would be to leave article untouched, and add article_id to image… and add an image type. This way it would be easy to say an article has many images, and use filter on image type to retrieve big, medium, small images.

I would use a “has many through” association. The association table would have an extra column for size (big, medium, small). Convenience functions could then select each specific size.

3 Likes

Hi all,

I’ve got the following so far, but it’s not working:

> belongs_to :image, ZkPortal.Image, foreign_key: "image_big_id"
> belongs_to :image, ZkPortal.Image, foreign_key: "image_medium_id"
> belongs_to :image, ZkPortal.Image, foreign_key: "image_small_id"

I know that I can use a “has many through” association but it is not necessary so I am trying to see if I can make it work without it.

Best,
Michal

You cannot use :image for all relations… How could the system choose which image is the good one?

That is why I suggested to use :big_image, etc.

1 Like

Yes, I understand now :slight_smile:

Thank you for your help.

Can someone recommend a book about Ecto?

Best,
Michal

Have a look here…

https://elixirforum.com/t/programming-ecto-pragprog/13287

Note the Forum discount mentioned in the first post :wink:

I would use a has_many with a size column. As of Ecto 3, you can use where on associations. So you can do something like:

has_one :big_image`, Image, where: [size: :big]
has_many :medium_images`, Image, where: [size: :medium]

The advantage of this approach is that you don’t have to use a foreign key for image type. That doesn’t really make much sense.

Just be careful that where in the association handled at compile time, so you can’t pass to it the same things you would pass to the Ecto query where. But in this case, it should be just fine.

See the Filtering Associations section in the has_many Ecto docs.

1 Like