активная запись рельсов has_many пользовательский запрос

возможно ли иметь активную запись has_many ассоциаций, но у меня есть особое условие.

class Team < AR
  has_many :matches, query: 'team1 == ID or team2 == ID'
end

class Match < AR
  attr_accessible :team1, :team2
end

person Fajarmf    schedule 12.08.2012    source источник


Ответы (3)


Вот потенциальное решение:

class Team < AR
  def matches
    Match.where("team1 = ? or team2 = ?", id, id) # or: { team1: id, team2: id }
  end
end
person DRobinson    schedule 12.08.2012
comment
Выполняя второй подход, должен ли я удалить много ассоциаций? - person Fajarmf; 12.08.2012
comment
Да, и замените #{ID} на #{id}, а одинарные кавычки на двойные. Обратите внимание, что вы потеряете многие преимущества ассоциации, такие как кэширование. Каждый раз, когда вы вызываете Team#matches, вы получаете новый объект Relation, который инициирует новый запрос к базе данных. - person Michaël Witrant; 12.08.2012
comment
поможет ли сохранить объект Relation? Я сам не уверен, но я думаю, что это предотвратит создание другого объекта, верно? - person Fajarmf; 12.08.2012
comment
Второй подход на самом деле не приведет к немедленному запуску базы данных. Во всяком случае, не из моего опыта - .where() этого не делает (по крайней мере, в последних версиях Rails), поэтому вы можете связать другие вещи, изменяющие запрос БД, в запросе, и он будет работать как один запрос даже со вторым пример. - person DRobinson; 12.08.2012
comment
Кроме того, да, второй подход означает, что вы должны удалить файл has_many. :) - person DRobinson; 12.08.2012
comment
Являются ли эти запросы безопасными для SQL-инъекций? - person Charles Brocchiero; 12.08.2019
comment
@CharlesBrocchiero Нет! Не интерполируйте строки, как я написал здесь. Мои извинения, это было написано, когда я был довольно новым. Use? и дополнительные аргументы для идентификаторов. - person DRobinson; 13.08.2019
comment
@CharlesBrocchiero Я удалил первую идею и обновил вторую, чтобы она была безопасной для sql-инъекций. Спасибо, что спросили об этом / указали на это. Надеюсь, люди не используют небезопасный код. - person DRobinson; 13.08.2019
comment
Хорошо, рад быть полезным! У меня было предчувствие, но пока не было времени его изучить. Это выглядит лучше! - person Charles Brocchiero; 13.08.2019

Вы можете использовать finder_sql, но он будет объявлен устаревшим в Rails 4, и я не уверен, что есть новый способ сделать это:

class Team < AR
  has_many :matches, finder_sql: proc { "SELECT * FROM matches WHERE (matches.team1 = #{id} or matches.team2 = #{id})" }
end

Другое решение:

class Team < AR
  has_many :matches_as_team1, class_name: "Match", foreign_key: "team1"
  has_many :matches_as_team2, class_name: "Match", foreign_key: "team2"
  def matches
    matches_as_team1 | matches_as_team2
  end
end

В этом решении результатом Team#matches является массив, а не Relation, поэтому вы не сможете делать такие вещи, как team.matches.limit(10).

person Michaël Witrant    schedule 12.08.2012
comment
я предпочитаю иметь отношения возможности. - person Fajarmf; 12.08.2012
comment
Затем используйте первое решение с finder_sql. - person Michaël Witrant; 12.08.2012
comment
Обратите внимание, что finder_sql должен принимать proc. -> недостаточно - person Ben Simpson; 23.01.2016

Я бы предпочел сохранить вашу ассоциацию как обычно и позже применить запрос с условием where.

class Team < AR
  has_many :matches

  scope :team_details, lambda {|id1,id2| matches.where("team1 = ? OR team2 = ?",id1,id2)} 
end

команда (объект команды)

Тогда позвони

team.team_details(id1,id2)
person AnkitG    schedule 12.08.2012
comment
Вы не должны использовать нотацию #{} с ? - она ​​используется внутри строк, но на ваши переменные ссылаются вне строки. - person DRobinson; 12.08.2012