Verbinden die gleiche Tabelle zweimal mit Bedingungen

Gibt es Situationen, wo ActiveRecord stellt die alias-Tabelle name, wenn es gibt mehrere Verknüpfungen mit der gleichen Tabelle. Ich bin in einer situation stecken, wo diese Verknüpfungen enthalten die Bereiche (mittels 'merge').

Habe ich eine viele-zu-viele-Beziehung:

Modelle table_name: users

Zweiten Modelle table_name: posts

Join-Tabelle name: access_levels

Post hat viele Nutzer durch access_levels und Umgekehrt.

Sowohl die User-Modell und die Post-Modell teilen sich die gleiche relation:

has_many :access_levels, -> { merge(AccessLevel.valid) }

Rahmen innerhalb der AccessLevel Modell sieht wie folgt aus:

  # v1
  scope :valid, -> {
    where("(valid_from IS NULL OR valid_from < :now) AND (valid_until IS NULL OR valid_until > :now)", :now => Time.zone.now)
  }

  # v2
  # scope :valid, -> {
  #   where("(#{table_name}.valid_from IS NULL OR #{table_name}.valid_from < :now) AND (#{table_name}.valid_until IS NULL OR #{table_name}.valid_until > :now)", :now => Time.zone.now)
  # }

Ich würde gerne call sth wie diese:

Post.joins(:access_levels).joins(:users).where (...)

ActiveRecord erzeugt einen alias für den zweiten join ('access_levels_users'). Ich möchte diese Tabelle referenzieren Namen in der 'gültigen' Bereich-der AccessLevel Modell.

V1 offensichtlich erzeugt eine PG::AmbiguousColumn-Fehler.
V2 Ergebnisse, indem die beiden Bedingungen mit access_levels., das ist semantisch falsch.

Dies ist, wie ich das generieren der Abfrage: (vereinfacht)

# inside of a policy
scope = Post.
  joins(:access_levels).
  where("access_levels.level" => 1, "access_levels.user_id" => current_user.id)

# inside of my controller
scope.joins(:users).select([
        Post.arel_table[Arel.star],
        "hstore(array_agg(users.id::text), array_agg(users.email::text)) user_names"
      ]).distinct.group("posts.id")

Den generierten query sieht wie folgt aus (mit der valid Umfang v2 von oben):

SELECT "posts".*, hstore(array_agg(users.id::text), array_agg(users.email::text)) user_names

  FROM "posts"
  INNER JOIN "access_levels" ON "access_levels"."post_id" = "posts"."id" AND (("access_levels"."valid_from" IS NULL OR "access_levels"."valid_from" < '2014-07-24 05:38:09.274104') AND ("access_levels"."valid_until" IS NULL OR "access_levels"."valid_until" > '2014-07-24 05:38:09.274132'))
  INNER JOIN "users" ON "users"."id" = "access_levels"."user_id"
  INNER JOIN "access_levels" "access_levels_posts" ON "access_levels_posts"."post_id" = "posts"."id" AND (("access_levels"."valid_from" IS NULL OR "access_levels"."valid_from" < '2014-07-24 05:38:09.274675') AND ("access_levels"."valid_until" IS NULL OR "access_levels"."valid_until" > '2014-07-24 05:38:09.274688'))

  WHERE "posts"."deleted_at" IS NULL AND "access_levels"."level" = 4 AND "access_levels"."user_id" = 1 GROUP BY posts.id

ActiveRecord stellt eine propriate alias 'access_levels_posts" für die zweite Verknüpfung die access_levels Tabelle.
Das problem ist, dass die zusammengeführten valid-Präfixe für den Gültigkeitsbereich der Spalte mit 'access_levels' statt 'access_levels_posts'. Ich habe auch versucht, aus arel zu generieren Umfang:

# v3
scope :valid, -> {
  where arel_table[:valid_from].eq(nil).or(arel_table[:valid_from].lt(Time.zone.now)).and(
    arel_table[:valid_until].eq(nil).or(arel_table[:valid_until].gt(Time.zone.now))
  )
}

Die resultierende Abfrage gleich bleibt.

  • deine Frage ist ein wenig verwirrend, aber ich denke, ich weiß, was Sie tun möchten. ändern Sie die valid Umfang zu joins(:user).where("(valid_from IS NULL OR valid_from < :now) AND (valid_until IS NULL OR valid_until > :now)", now: Time.zone.now).where(users: { active: true, or: something })
InformationsquelleAutor Alex | 2014-07-23
Schreibe einen Kommentar