Рельсы: В моделях A has_many B принадлежит_в C возвращает A, где B принадлежит C, а B создан совсем недавно для данного A? - PullRequest
3 голосов
/ 11 февраля 2010

У меня есть три модели 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 могут быть представлены, например, как Pets (A), PetsName (B) и Names (C). PetsNames даются Pets в определенное время, и любое данное имя может быть дано многим Pets. Любой питомец может иметь много Имен (через отношения). Для данного Имени я хочу всех Питомцев, в которых это Имя является последним созданным PetName для этого Питомца. Звонок может выглядеть примерно так: @name.pets.most_recently_named_as

1 Ответ

4 голосов
/ 13 февраля 2010

Rails способ сделать это является именованной областью для домашних животных.

Примерно так:

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
...