Как избежать короткого замыкания на

Я работаю с Ruby on Rails и хочу проверить две разные модели:

if (model1.valid? && model2.valid?)
...
end

Однако оператор «&&» использует оценку короткого замыкания (т.е. он оценивает «model2.valid?», Только если «model1.valid?» Истинно), что предотвращает выполнение model2.valids, если model1 недействителен.

Есть ли эквивалент «&&», который не использовал бы оценку короткого замыкания? Мне нужно оценить два выражения.


person Community    schedule 28.01.2009    source источник
comment
Зачем из любопытства оценивать и то, и другое? Обычно, если они не имеют побочных эффектов, короткое замыкание желательно. А с чего бы #valid? есть побочные эффекты?   -  person    schedule 28.01.2009
comment
Две модели связаны с одной и той же формой: в конце концов, они должны быть проверены для выполнения действия. Побочного эффекта нет, это просто потому, что это две модели на одной форме.   -  person    schedule 28.01.2009
comment
Ну ... короткое замыкание - это именно то, что вы хотите. ЕСЛИ модель 1 недействительна, зачем тогда проверять модель 2?   -  person    schedule 28.01.2009
comment
Честно говоря, проверка обеих моделей одновременно позволяет сообщать пользователю об ошибках по обеим моделям по отдельности. Досадно получать уведомления об ошибке валидации в модели 2 только после того, как вы исправили ошибку модели 1.   -  person Paul Smith    schedule 28.01.2009
comment
Действительно, но следите за разделением ответственности. #действительный? должен только проверять, а не уведомлять пользователя об ошибках. Следовательно, предложение if будет вводиться в всех и только случаях, когда это необходимо. Затем уведомление должно выполняться отдельно от проверки, а именно внутри предложения if.   -  person    schedule 28.01.2009
comment
Для справки: #valid? НЕ уведомляет пользователя об ошибках. Он только заполняет ошибками массив ошибок модели. Затем контроллер снова показывает новое / редактируемое представление, которое затем показывает ошибки.   -  person Samuel    schedule 28.01.2009


Ответы (6)


Попробуй это:

([model1, model2].map(&:valid?)).all?

Он вернет true, если оба действительны, и создаст ошибки в обоих экземплярах.

person Codebeef    schedule 28.01.2009
comment
Спасибо! Отличный код! Кстати, я обнаружил «все?» метод, и я не знал, что метод 'map' можно использовать с таким синтаксисом ('&: valid?'). Я воспользуюсь этим решением. - person ; 28.01.2009
comment
@BrenoSalgado, почему бы и нет? Я думаю наоборот: это очень крутой способ обойти оценку короткого замыкания. (И я это делаю, потому что: использование карты, &: имя_метода и все такое?) - person Leonel Galán; 18.10.2012
comment
Использование map излишне, Enumerable # all? занимает блок. - person crazymykl; 31.01.2014
comment
Обратите внимание, что шаг map(&:valid?) важен: [model1, model2].all?(&:valid?) - это операция короткого замыкания (он не будет собирать ошибки на model2, если есть ошибки на model1.) - person Elliot Nelson; 19.03.2014
comment
Для меня это более многословно и запутанно, чем просто установить результат одного действительного? сначала вызовите переменную. Если вы не хотите устанавливать переменную и не хотите использовать оператор & на том основании, что другие могут не получить его, я бы посоветовал потратить лишние два цента и назвать действительным? дважды в массиве, как это делает Malclocke. - person cesoid; 05.03.2015
comment
С другой стороны, если у вас их три и более действительных? проверки, это могло стоить того. Также может помочь удаление крайних скобок, я не думаю, что они необходимы, и у меня это работает без них. - person cesoid; 06.03.2015
comment
Для меня это лучший ответ. Самый рубиновый. Представьте себе массив, размер которого вы заранее не знаете. Также вы не можете использовать all?, так как он замыкается на первом ложном, поэтому вы не получаете сообщения об ошибках на каждой модели. - person Kris; 02.07.2015

& работает нормально.

irb(main):007:0> def a
irb(main):008:1> puts "a"
irb(main):009:1> false
irb(main):010:1> end
=> nil

irb(main):011:0> def b
irb(main):012:1> puts "b"
irb(main):013:1> true
irb(main):014:1> end
=> nil

irb(main):015:0> a && b
a
=> false

irb(main):016:0> a & b
a
b
=> false

irb(main):017:0> a and b
a
=> false
person Paul Smith    schedule 28.01.2009
comment
valid - это метод, который запускает проверки экземпляра ActiveRecord, заполняя связанные ошибки, чтобы о них можно было сообщить пользователю. - person Codebeef; 28.01.2009
comment
Обратите внимание, что вы должны быть осторожны с левой частью & | или оператор ^, поскольку это методы, определенные только для TrueClass и FalseClass, AFAICT ... - person Mike Woodhouse; 28.01.2009
comment
Хороший аргумент, мистер Мэтт: сообщать об ошибках одновременно в обеих моделях - достойная цель. Удален комментарий о запахе плохого кода :) - person Paul Smith; 28.01.2009
comment
@Mike: Интересно - мне нужно будет провести дополнительное расследование IRB. PS Я люблю irb за такие расследования! - person Paul Smith; 28.01.2009
comment
Интересно! Я никогда не обращал внимания на & и | в логическом контексте, поскольку я автоматически читаю их как побитовые операции. - person cpm; 30.01.2009
comment
Мне это нравится, и я бы сделал это, если бы уделял больше внимания поднятию планки по сравнению с немедленной читабельностью, но я действительно думаю, что большинство программистов вряд ли поймут сразу. Я видел, как разные люди делали разный выбор в зависимости от ситуации. - person cesoid; 05.03.2015

Как насчет:

if [model1.valid?,model2.valid?].all?
  ...
end

Работает для меня.

person malclocke    schedule 02.06.2010

Оцените их отдельно и сохраните результат в переменной. Затем используйте простой && между этими логическими значениями :)

person mmx    schedule 28.01.2009


Вместо создания дополнительного массива с картой вы можете передать блок в all?.

[model_instance_1, model_instance_2].all? {|i| i.valid? }
person August Lilleaas    schedule 28.01.2009
comment
Вау, хотя этот ответ не такой короткий, как ответ Мэтта, он действителен и намного лучше, чем &. - person Samuel; 28.01.2009
comment
Почему за этот ответ проголосовали против? Что-то не так с этим ответом, что не сразу очевидно? - person Eliza Brock Marcum; 29.01.2009
comment
@Paul Производительность и безвестность. Символ # to_proc был намного медленнее, чем передача блока в более старых версиях ruby. (Впрочем, это не проблема с двумя элементами.) Это относительно новое дополнение к основной библиотеке, использующее старый, но не часто используемый синтаксис приведения типов. - person cpm; 30.01.2009