Странное поведение в однострочном рубиновом предложении, содержащем блок и предложение 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 извините за мой английский

Другие вопросы по тегам