Странное поведение в однострочном рубиновом предложении, содержащем блок и предложение if
Я не знаю, почему эти два фрагмента кода ведут себя по-разному в Ruby 1.8.7, поскольку один кажется однострочным вариантом другого.
Первый кусок кода (работает как надо):
if @type.present?
type = @type
orders = Order.where{type.eq(type)}
end
Однострочная версия (она вообще не работает, нет ошибок, но, похоже, тоже не выполняется):
orders = Order.where{type.eq(type)} if (type = @type).present?
ПРИМЕЧАНИЕ: я использую самоцвет squeel, поэтому блок следует методу where. Кроме того, тип переменной должен захватывать переменную экземпляра @type, поскольку контекст выполнения изменяется внутри блока, а переменные экземпляра не являются общими для основного контекста и контекста блока.
ПРИМЕЧАНИЕ 2: Я должен использовать Ruby 1.8.7 по устаревшим причинам.
Любая идея? Спасибо!
3 ответа
Есть проблема с порядком разбора вашего кода. Переменные должны быть определены до их использования.
Даже если переменные определены внутри if
предложения операторов "просачиваются" в текущую область, они не просачиваются "назад" в коде Ruby.
Ruby немного любопытно, что переменные должны быть определены до того, как синтаксический анализатор проанализирует код. Разбор выполняется сверху вниз и слева направо.
Следовательно, поскольку переменная type
определяется после вашего кода блока, где вы его используете, он не будет доступен в блоке.
Пример:
>> 3.times { puts x } if (x = 123)
NameError: undefined local variable or method `x' for main:Object
Причина, по которой вы не получаете сообщение об ошибке, заключается в том, что в Ruby 1.8 type
это метод, который является синонимом Object#class
,
Итак, что на самом деле делает ваш код (вероятно):
orders = Order.where{type.eq(this.class)} if (type = @type).present?
Чтобы исправить это, вы должны определить type
прежде чем использовать его. Поэтому вы не можете превратить это в однострочник, если просто не сделаете это вместо этого:
orders = Order.where{type.eq(@type)} if @type.present?
В общем, в Ruby 1.8 не стоит использовать type
в качестве переменной в моделях Rails, из-за Object#class
проблема, скорее всего, принесет вам головную боль в долгосрочной перспективе.
Схожая проблема, с которой я столкнулся, заключалась в том, что "тип" - это ключевое слово в базе данных, оно позволяет нашей модели иметь поле "тип", но оно странным образом работает в разных условиях. если изменение имени является вариантом для вас, проверьте после изменения, работал для меня...
Gem Squeel использует instance_eval
метод, когда вызывает блок, который передается where
, Итак, нет @type
в качестве примера. Если вы хотите использовать методы или переменные из другого контекста, попробуйте включить их в метод my
с блоком
orders = Order.where { type.eq my { @type } } if @type.present?
PS извините за мой английский