2014-02-04 4 views
1

Я создаю activerecord для моделирования дерева беседы, используя тип столбца массива, чтобы представить материализованный путь места записи в этом дереве, используя postgres 9.1, rails 4.0 и pg gem.Как получить доступ к текущему значению id в инициализаторе activerecord?

Что я действительно хочу сделать, это получить доступ к currval ('conversations_id_seq'), когда я создаю новый объект беседы, чтобы я мог передать [grandparent_id, parent_id ... current_id] в качестве массива в инициализатор объекта. Таким образом, я могу указать, что этот столбец не является нулевым, как ограничение базы данных, и в случае бесцельного разговора по умолчанию он по умолчанию [current_id].

Проблема, с которой я сталкиваюсь, - получить доступ к значению идентификатора модели, прежде чем я сохраню его в первый раз. Я всегда мог бы расслабить не нулевое ограничение и добавить крюк after_create, но он чувствует себя глупым. Я надеюсь, что есть способ, которым я могу захватить значение, которое вставляется в @id внутри инициализатора, до первого сохранения в базе данных.

EDIT, чтобы уточнить, для награды: в идеальном мире был бы специальный токен, который я мог бы передать методу создания объекта: Conversation.create (reply_chain: [: lastval]), где камень взял это mean lastval() в сгенерированном SQL.

+1

Пустой массив путей может иметь больше смысла, чем массив реляционных массивов для корневых узлов, тогда пути становятся «parent.path + [parent.id]», и проблема последовательности исчезает. –

ответ

4

что-то вроде:

def before_create 
    self.id=Conversation.connection.execute("SELECT nextval('conversations_id_seq')") 
    self.path = [... , self.id]; 
    true 
end 

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

+1

Aha! Да, это явно то, что я должен был сделать. Это более или менее работает как написано (кроме того, что connection.execute возвращает PG :: Result, из которого вы должны получить фактическое значение int). Спецификации проходят, и это все еще безопасно. – pfooti

0

Вы можете псевдоним атрибута, если вам не нужен столбец в базе данных.

alias_attribute :current_id, :id 

Или вы можете запросить идентификатор, когда вам это нужно.

def self.last_val 
    ActiveRecord::Base.connection.execute("SELECT lastval('conversations_id_seq')") 
end 

def self.next_val 
    ActiveRecord::Base.connection.execute("SELECT nextval('conversations_id_seq')") 
end 

Conversation.create(reply_chain: Conversation.next_val) 

Использование after_save не является самым уродливым кодом.

+0

Определение метода last_val похоже на то, что мне нужно, но время кажется выключенным - если я попытаюсь вызвать Conversation.create (reply_chain: [Conversation.last_val]), например, вызов last_val будет оцениваться перед вызовом create , – pfooti

Смежные вопросы