Как использовать замыкания в контроллере Rails? - PullRequest
2 голосов
/ 25 мая 2020
class MyController < ApplicationController
  def getuser
    data = params[:data]
    first.call
  end

  first = lambda { user = User.first.name + data }
end

Но в виду получаю

NameError undefined local variable or method `first' for

Спасибо за помощь

1 Ответ

4 голосов
/ 25 мая 2020

Замыкание лямбды или про c собирается при создании лямбды. Таким образом, тело лямбда имеет доступ ко всем локальным переменным, которые были определены и видимы в точке, где была создана лямбда. Это не включает другие переменные, определенные только при вызове лямбда.

Таким образом, вы должны передать в него любые данные, которые необходимы лямбда (и которые еще не были доступны в замыкании, когда лямбда была создана) с помощью параметр.

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

class MyController < ApplicationController

  # define a local variable which will be available in the lambda's closure
  scope = ENV['scope']

  # Assign the lambda to a constant. That way, it can be resolved
  # by every method in the current class
  FIRST = lambda do |data|

    # The scope variable is available here when the lambda is called
    # since it is available in the closure from the lambda's creation.
    #
    # Since the data variable is not available during the lamda's
    # creation, we need to get it from a parameter from the caller.
    User.where(scope: scope).first.name + data
  end

  def getuser
    data = params[:data]
    FIRST.call(data)
  end
end

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

class MyController < ApplicationController
  def getuser
    data = params[:data]
    first(data)
  end

  private

  def first(data)
    User.first.name + data
  end
end

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

Javascript (где анонимные функции обычно передаются с закрытием, немного похожим на лямбда-выражения Ruby), вы должны попытаться адаптироваться к Ruby -проходу и избегать такой конструкции в пользу объектов с явными методами .

...