Подклассы ActiveRecord с permalink_fu в движке рельсов - PullRequest
1 голос
/ 27 августа 2010

Этот вопрос связан с расширением методов класса в Ruby, возможно, более конкретно с тем, как это делает permalink_fu.

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

class MyScope::MyClass < ActiveRecord::Base
  unloadable
  self.abstract_class = true
  has_permalink :name
end

class MyClass < MyScope::MyClass
  unloadable
  #has_permalink :name # This seems to be required
end

Есть ли что-то в способе, которым permalink_fu смешивается, что вызывает эту проблему?

Я использую гем permalink-v.1.0.0 http://github.com/goncalossilva/permalink_fu

1 Ответ

0 голосов
/ 01 сентября 2010

После изучения этого я теперь вижу, что проблема связана с тем, как permalink_fu проверяет, должна ли она создавать постоянную ссылку или нет. Он проверяет это, проверяя, является ли поле permalink_field класса пустым или нет.

Что такое поле постоянных ссылок? Когда вы делаете

class Parent < ActiveRecord::Base
  has_permalink :name
end

class Child < Parent
end

Вы можете получить доступ к постоянной ссылке, написав Parent.new.permalink или Child.new.permalink. Имя этого метода можно изменить, написав

class Parent < ActiveRecord::Base
  has_permalink :name 'custom_permalink_name'
end

Если это так, постоянная ссылка будет доступна при записи Parent.new.custom_permalink_name (или Child.new.custom_permalink_name).

В чем проблема с этим? Методы доступа permalink_field определены в метаклассе Parent:

class << self
  attr_accessor :permalink_field
end

Когда вы запускаете метод has_permalink, он вызывает Parent.permalink_field = 'permalink'.

Проблема в том, что хотя метод permalink_field доступен во всех подклассах, его значение сохраняется в классе, который он вызвал. Это означает, что значение не распространяется на подклассы.

Таким образом, поскольку permalink_field хранится в классе Parent, дочерний элемент не наследует значение, хотя он наследует методы доступа. Поскольку Child.permalink_field пусто, should_create_permalink? возвращает false, а Child.create :name => 'something' не создает постоянную ссылку.

Возможным решением было бы заменить attr_acessors в метаклассе на cattr_accessors в классе (строки 57–61 в файле permalink_fu.rb).

Заменить

class << base
  attr_accessor :permalink_options
  attr_accessor :permalink_attributes
  attr_accessor :permalink_field
end

с

base.cattr_accessor :permalink_options
base.cattr_accessor :permalink_attributes
base.cattr_accessor :permalink_field

Обратите внимание, что это сделает недействительными любые возможные настройки подкласса. Вы больше не сможете указывать различные параметры для подклассов, поскольку эти три атрибута совместно используются Parent и всеми его подклассами (и подклассами).

...