Join two Rails ActiveRecord Models in a third Model

C.Diezinger Source

My problem is as follows: I have two models, A and B. Now I want to create a third model C which references the other two models A and B, so that an object of Model C can "hold" several objects of A and B.

What I want to do with it: Model A and B both have an attribute called :hero_image. Now I want to show all :hero_images of A and B, which are joined in the object of C.

Actually I´m not sure if I need model C at all. I have projects and competitions and I want to join them in a collection.

projects = Project.where.not(hero_image: nil)
competitions = Competition.where.not(hero_image: nil)

Now I want to join those 2 collections.

I was chasing the wrong rabbit. All I need is

collection_of_proj_and_comps = projects + competitions

Thank you for your advice. Did let me rethink the problem.

ruby-on-railsrubyrails-activerecord

Answers

answered 4 weeks ago Jared #1

You can still use the union pipe operator to join the two lists of ActiveRecord Objects.

projects = Project.where.not(hero_image: nil)
competitions = Competition.where.not(hero_image: nil)
collection_of_proj_and_comps = projects | competitions

This will get you an Array of all of those objects in the same list.

I would just add tests to make sure they both "quack" like each other. So add tests to ensure they both respond to hero_image and other things you'll be doing with this unioned collection later on.


Old answer for pre-edited question

For ease of typing out the syntax I'll remake the scenario with Users having many Posts and Comments.

In your User class you could do something like

@user.comments.pluck(:hero_image) | @user.posts.pluck(:hero_image)

This would create two arrays then union then, removing any duplicate entries from overlap between the two queries.

answered 4 weeks ago AJFaraday #2

It really depends what you're trying to achieve but you might try adding this view to your database (not to be confused with views in MVC).

create or replace view hero_images as
select 
  hero_image, 
  id source_id,
  'Project' source_type
from projects
union all
select
  hero_image,
  id source_id,
  'Competition' source_type
from competitions

(Note that syntax may be different for your database, this is Oracle syntax).

If you then query these in the database, you'll see the hero image, and where it's come from.

If you then write a model called HeroImage, it should return the data you want.

You might want a link back to the source, too

class HeroImage < ActiveRecord::Base

  primary_key :source_id

  belongs_to :source, polymorphic: true

end

I'm not sure if this is what you want, but it should get all that data together.


What this is doing:

A database view is a canned SQL statement which can be queried like a table (but is read-only).

A union statement will return the results of two or more SQL statements with the same column names as a single table of results.

A polymorphic reference uses *_type to decide which model the related object belongs to and *_id to find a specific instance.

answered 4 weeks ago C.Diezinger #3

projects = Project.where.not(hero_image: nil)
competitions = Competition.where.not(hero_image: nil)

I was chasing the wrong rabbit. All I need is

collection_of_proj_and_comps = projects + competitions

comments powered by Disqus