молча пропустить добавление с обратным вызовом ассоциации before_add вместо создания исключения? - PullRequest
7 голосов
/ 01 сентября 2011

Я пытаюсь сделать это

 has_many :roles, :before_add => :enforce_unique

 def enforce_unique(assoc)
   false if exists? assoc
 end

Из документов: «Если обратный вызов before_add вызывает исключение, объект не добавляется в коллекцию». Использование false выше не препятствует добавлению, поэтому я вынужден сделать это:

 def enforce_unique(assoc)
   raise if exists? assoc
 end

Таким образом, это правда, что он не добавляется, но он также вызывает исключение, которое должно быть обработано. Не очень полезно для меня здесь. Я бы предпочел, чтобы это больше походило на обычный обратный вызов AR before_save, где возврат FALSE также предотвращает сохранение (или добавление), но не вызывает исключение.

В этом случае выше, я бы предпочел, чтобы это просто не добавлялось ассоциированным молча. Есть ли способ сделать это? Я что-то пропустил? Или здесь исключение является единственным вариантом?

Ответы [ 4 ]

2 голосов
/ 18 июля 2014

Я думаю, что для ее решения нужно использовать throw и catch, которые в Ruby предназначены для управления потоком.Вызов исключения не очень подходит, поскольку это не исключительное обстоятельство.

Я закончил тем, что сделал:

catch(:duplicate) do
  association.create({})
end

А затем в обратном вызове before_add я сделал:

if(Class.where({}).first)
  throw :duplicate
end

Подробнее о броске / улове здесь:

http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue-im-so-confused/

1 голос
/ 08 сентября 2012

этот вопрос немного устарел, но недавно я столкнулся с той же проблемой.вот как я это решил:

def enforce_unique |obj, x|
  v = obj.roles
  if i = v.index(x)
    v.slice! i
  end
end
1 голос
/ 01 сентября 2011

Если ассоциация не является полиморфной, вы можете сделать что-то вроде:

validates_uniqueness_of :name_of_model

внутри роли, где name_of_model нам, с чем вы ассоциируете

0 голосов
/ 25 июля 2014

Поскольку этот вопрос касается сохранения, а не предотвращения его временного включения в список (например, контроллером, который не заинтересован в управлении своими моделями), вы можете попробовать переопределить сохранение в связанной модели и просто не сохранять его, если рольСуществуют:

class Role < ActiveRecord::Base
  belongs_to :user, inverse_of: :roles

  def save
    super unless self.new_record? && user.has_existing_role?(self)
  end
end

Sidenote: Я не покупаю тощий аргумент контроллера при использовании с шаблоном Active Record, поскольку бизнес-логику нужно где-то поместить.При плохом шаблоне бизнес-области, таком как Active Record (не относящемся к гему Ruby AR), ему действительно необходимо существовать на уровне выше (т.е. на уровне контроллера), вы можете использовать сервисные объекты или шаблон декоратора в качестве средства для достижения этой цели..

Другим подходом было бы переопределить методы обновления, такие как << для ассоциации, и молча отбросить роль, если она соответствует существующей.Подробная информация о переопределенных методах ассоциации приведена в документации ActiveRecord Class Class Methods

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...