Рельсы:С моделями A has_many B принадлежит C возвращает A, где B принадлежит C, а B является самым последним созданным для данного A?

StackOverflow https://stackoverflow.com/questions/2247257

Вопрос

У меня есть три модели A, B и C, где A has_many B; B belongs to C, и B has a created_on timestamp.C имеет множество от A до B.

Я хочу вернуться ВСЕ A где A имеет B , который принадлежит C , и где B - самый последний созданный B для этого A.

Я могу сделать это с помощью цикла метода.Можно ли это сделать исключительно с помощью named_scopes?, или есть какой-то другой элегантный / эффективный способ?

Согласно запросу для реального мира (TM) примеры A, B и C могут быть представлены, например, как Домашние животные (A), PetsName (B) и Names (C).Имена домашних животных присваиваются домашним животным в определенное время, и любое данное Имя может быть присвоено многим домашним животным.У любого питомца может быть много имен (ответ: через родство).Для данного Имени я хочу ВСЕ из домашних животных, у которых это Имя является самым последним созданным именем для этого Питомца.Вызов может выглядеть примерно так @name.pets.most_recently_named_as

Это было полезно?

Решение

Лучший способ сделать это - создать именованную область для домашних животных.

Что- то вроде этого:

class Pets
  has_many :pet_names
  has_many :names, :through => :pet_names

  named_scope :with_current_name, lambda {|name| 
    { :joins => "JOIN (pet_names pna, names) " +
        "ON (pna.pet_id = pets.id AND pna.name_id = names.id) " +
        "LEFT JOIN pet_names pnb " +
        "ON (pnb.pet_id = pets.id AND pna.created_at < pnb.created_at)", 
      :conditions => ["pnb.id IS NULL AND names.id = ? ", name]
    }
  }
end

Pets.with_current_name(@name)
@name.pets.with_current_name(@name)

Чтобы все было ориентировано на имена, вы всегда можете определить метод на C / Name, который вызывает именованную область.

Ты всегда мог бы сделать

class Name < ActiveRecord::Base
  has_many :pet_names
  has_many :pets, :through => :pet_names

  def currently_named_pets
    Pets.with_current_name(self)
  end
end

И

@name.currently_named_pets

Это довольно сложное соединение.Это показатель того, что вам, вероятно, следует переосмыслить способ хранения этой информации.Почему так важно, чтобы имена были в отдельной таблице?

Возможно, вам было бы лучше сделать что-то вроде этого:

После добавления name и old_name колонки для домашних животных:

class Pet < ActiveRecord::Base
  serialize :old_name, Array
  def after_initialization 
    @old_name ||= []
  end

  def name= new_name
    self.old_name << new_name
    self.name = new_name
  end

  named_scope :with_name, lambda {|name|
     { :conditions => {:name => name}}
  }
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top