0

У меня есть проверка ActiveRecord для некоторых записей, которые по умолчанию автоматически блокируют мое приложение-рельсы несколько версий записей с одинаковым значением строки следующим образом:Ruby: Как сохранить динамически сгенерированный список на уровне класса, так что список вычисляется только один раз и ТОЛЬКО ЕСЛИ класс вызван на

class Boat < ActiveRecord::Base# not actual class name, but I like boating 
    validates :boatname, :uniqueness => true 
end 

Я хотел бы добавить before_validation обратные вызов для моей модели, как так ...

require 'highline/import' #simplifies command prompt response code 
class Boat < ActiveRecord::Base 
    validates :boatname 

    before_validation do |r| 
    pre_existing = Boat.find_by_boatname(r.boatname) 
    if pre_existing 
     puts "whoa! found a boat that already exists with the name '#{r.boatname}':" 
     ap pre_existing #pretty prints the column names and values 
     resp = ask("press 'o' to overwrite, 'm' to modify the new boat name so it gets added") 
     if resp == "o" 
     #..code handling responses 
     end 
    end 

Но это вычислительно дорого абсурдного степень. Я думал об обращении с ним, как это, что приводит нас к моему актуальному вопросу:

require 'highline/import' #simplifies command prompt response code 
class Boat < ActiveRecord::Base 
    validates :boatname 
    @@existing_boats ||= all.map(&:boatname) 

    before_validation do |r| 
    if @@existing_boats.include?(r.boatname) 
     puts "whoa! found a boat that already exists with the name '#{r.boatname}':" 
     ap pre_existing #pretty prints the column names and values 
     resp = ask("press 'o' to overwrite, 'm' to modify the new boat name so it gets added") 
     if resp == "o" 
     #..code handling responses 
     end 
    end 

Это лучший способ справиться с что-то вроде этого? Соответствует ли он моим критериям загрузки только один раз за экземпляр ruby ​​/ rails и только если класс вызван? Я подумал, может быть, мне придется поместить компонент all.map(&:boatname) в лямбда или proc, чтобы предотвратить его загрузку каждый раз, когда рельсы инициализированы, но я не уверен, что это необходимо.

Принимая общую критику в отношении моего проектного подхода, но это не цель вопроса.

+1

Ваша вторая версия, вероятно, дороже, не менее (при условии, что у вас есть указатель на имя лодки) –

+1

Вы делаете это неправильно. Вещь, которая пытается создать «Boat's», должна выполнять «перезапись/изменение». У вас также должен быть уникальный индекс в 'boatname' в вашей базе данных, этот индекс должен сделать проверку подлинности существования очень быстрой. –

+0

Спасибо @FrederickCheung, этот комментарий стоил того, чтобы расспрашивать вопрос –

ответ

1

Вещь, которую Вы пытаетесь реализовать здесь

@@existing_boats ||= all.map(&:boatname) 

известен как кэширование. Как правило, кэширование заставляет вас обновлять кэшированные данные, как только они устаревают. Пусть 5 лодок будут сохранены внутри базы данных, что должно быть возвращено, когда пользователи сохраняют другие 10 лодок? Сохранение кэша внутри модели заставляет вас использовать некоторые внешние таймерные решения или дополнительные обратные вызовы модели для обновления кэшированного значения. Это можно решить проще, взгляните на this stackoverflow question и this tutorial.

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

Более подробно о том, что я не уверен, что здесь происходит:

resp = ask("press 'o' to overwrite, 'm' to modify the new boat name so it gets added") 

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

+0

, это не рельсы, я просто использую рельсы для ActiveRecord. Иногда я использую переднюю часть для служебных целей, но для всех интенсивных целей ее нет. –