Ruby on Rails - Какой метод мне следует переопределить для Album.first.photos? - PullRequest
2 голосов
/ 22 июля 2010

Я переопределил метод find для ActiveRecord::Base, и все прошло очень хорошо, теперь я могу его настроить.

def self.find(*args)
  # my custom actions 
  super(*args)
end

тогда

Album.find(1) #=> My custom result

Но теперь я хотел бы переопределить это:

Album.first.photos

и я не уверен, какой именно метод я должен переопределить, чтобы выполнить работу ... Я думаю о чем-то специально для ассоциативных запросов, но я не уверен: (

Мне нужно действовать по 'ActiveRecord :: Base', предлагая динамические классы, поэтому я не могу создать для этого метод photos, но метод, который будет взаимодействовать во всех моделях, которые я пробую.

Большое спасибо


Обновление

Для лучшего объяснения того, чего я пытаюсь достичь:

Создает подключаемый рубиновый драгоценный камень для использования с рельсами, и этот драгоценный камень может просто взять вашу структуру идентификатора из базы данных и преобразовать ее на лету в сокращенный идентификатор, как в bit.ly системе. но это делается на лету только с объявлением has_shortened :id для вашей модели, а затем все интерфейсы и запросы возвращаются, например, DH3 вместо 12, например, мне удалось заставить это работать в этой точке я нужно иметь дело с ассоциациями.

Следуйте за URL-адресом драгоценного камня http://github.com/ludicco/shortener, чтобы вы могли его проверить и не стесняйтесь выдвигать идеи, которые вам могут понадобиться для реализации, если вы считаете, что это хорошая идея.

Приветствия

Ответы [ 4 ]

2 голосов
/ 04 августа 2010

Средства доступа ассоциаций, которые вы определяете с помощью has_many, довольно сложны в ActiveRecord за сценой.Они фактически используют класс отражения для возврата прокси-объекта, который ведет себя как класс модели, но ограничивает его искатели внешним ключом (и, возможно, другими условиями).Если вы хотите углубиться в это, вы можете взглянуть на mirror.rb, association.rb, association / association_proxy.rb и association / association_collection.rb в гем ActiveRecord.

Однако вв конце концов, мы можем использовать средство доступа к ассоциации, как если бы это был сам класс, а ActiveRecord позаботится о том, чтобы передать требуемые дополнительные условия для поиска классов.

Это означает, что если вы вызываете Album.first.photos, то позадиСцена ActiveRecord вызывает Photo.find (с дополнительным условием для возврата только тех записей, которые имеют: album_id => Album.first.id).

Итак, если вы переопределите Photo.find, он вернет ваш измененныйрезультаты также, если вы используете его через Album.first.photos.Это волшебство ActiveRecord:)

Мой быстрый тест (запускался с Rails 2.3.8):

class Album < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :album

  def self.find (*args)
    puts "XXX running custom finder"
    super
  end
end

Консоль Rails:

> Photo.all
XXX running custom finder
Photo Load (0.4ms)   SELECT * FROM "photos" 
=> [#<Photo id: 1, album_id: 1>, … ] 

> Album.first.photos
Album Load (0.4ms)   SELECT * FROM "albums" LIMIT 1
XXX running custom finder
Photo Load (0.3ms)   SELECT * FROM "photos" WHERE ("photos".album_id = 1) 
=> [#<Photo id: 1, album_id: 1>, … ] 
1 голос
/ 22 июля 2010

Поскольку Album.first возвращает экземпляр Album, вы должны переопределить метод photos для самого класса Album:

class Album < ActiveRecord::Base

  # ...

  def photos(*args)
    if my_condition_is_met
      // my custom handler
    else
      super
    end
  end

  # ...

end

Теперь, если вы уверены, что это необходимо для каждой отдельной моделиНапример, я бы предпочел изолировать его в модуле:

module Photo
  def photos(*args)
    if my_condition_is_met
      // my custom handler
    else
      super
    end
  end
end

и заново открыть ActiveRecord::Base class:

class ActiveRecord::Base
  include Photo
end

Таким образом, вы получаете модульность для своего решения, заставляя его действовать как«Плагин».

Одна дополнительная и не связанная с этим заметка: вам не нужно звонить super(*args), поскольку вызов только super передаст все параметры, которые вы получили.

РЕДАКТИРОВАТЬ: Малое форматирование

0 голосов
/ 08 августа 2010

Взгляните на плагин friendly_id (http://github.com/norman/friendly_id http://norman.github.com/friendly_id/file.Guide.html), он делает то, что вам нужно: генерировать псевдоним идентификатора для модели. Вы можете определить собственный метод для создания слаг.Оставьте id поле в модели

Для пользовательского использования #find: finder_sql опция:

class Album < ActiveRecord::Base
  has_friendly_id :short_id

  has_many :photos, :finder_sql => 'select * from photos where album_id="#{short_id}"'
end

>> Album.last.photos
select * from photos where album_id="t54"
0 голосов
/ 07 августа 2010

Есть ли какая-то особая причина, по которой вы не можете сделать это с расширением ассоциации?

http://ryandaigle.com/articles/2006/12/3/extend-your-activerecord-association-methods

Непосредственное взаимодействие с прокси-объектами вызывает проблемы.Но если вы просто хотите отменить поиск, это может сделать это.

...