【问题标题】:Pass url params hash in controller to another method, becomes nil将控制器中的 url 参数哈希传递给另一个方法,变为 nil
【发布时间】:2013-01-09 15:34:11
【问题描述】:

我有一个匹配 /edit_account => accounts#edit 的路由,因为没有提供帐户 ID,它应该使用当前用户 ID,并且 account#edit 方法与 /accounts/[:id]/edit 共享。

class AccountController < ApplicationController
  ...
  def edit
    # This doesn't work:
    params = retrieve_id_if_missing(params)

    # This works:
    # aHash = params
    # params = retrieve_id_if_missing(aHash)
  end

  def retrieve_id_if_missing(params)
    # raise params.inpect => returns nil at this point
    if params[:id].nil? and !logged_in?
      redirect_to root_path
    else params[:id].nil?
      params[:id] = current_user.id
    end
      params
  end
end

我遇到的问题是params 在传递给类方法retrieve_id_if_missing 时变成了nil。但是,如果我将 params 分配给另一个变量。例如,aHash,在将其传递给 retrieve_id_if_missing 之前,它将包含预期的数据,{"action" =&gt; "edit", "controller" =&gt; "account"}

我试图寻找一个原因,但没有找到原因,有人可以向我解释为什么会发生这种情况吗?

【问题讨论】:

    标签: ruby-on-rails controller ruby-on-rails-3.2


    【解决方案1】:

    你试过了吗

    class AccountController < ApplicationController
      ...
      def edit
    
        retrieve_id_if_missing
    
    
      end
    
      def retrieve_id_if_missing()
        if params[:id].nil? and !logged_in?
          redirect_to root_path
        else params[:id].nil?
          params[:id] = current_user.id
        end
          params
      end
    end
    

    我相当肯定参数将在方法的范围内。

    无论如何,请为此查看 gem 设计。它应该有你想要的一切以及更多

    有了设计,你就可以使用

    before_filer :authenticate_user!
    

    在控制器的顶部

    https://github.com/plataformatec/devise

    【讨论】:

    • 虽然这可行并且绝对更干净,但我仍然不明白为什么它的行为方式与我的问题中解释的方式相同。注意:这不是生产代码(或永远不会),所以我现在对使用正确的 gem 不感兴趣。
    • 我不是 100% 确定机制,但 ruby​​ 通过引用传递变量。因此,您将对 params 的引用传递给函数,然后该函数将对同一对象的引用传递回以覆盖该对象。也许在那条链中,ruby 正在创建一个新的 nil 对象来解决这个问题。
    【解决方案2】:

    Ruby 解释器将params 视为局部变量,并在看到赋值时将其初始化为nil。这发生在它执行retrieve_id_if_missing 之前。

    这就是为什么在调用方法之前显式为局部变量赋值可以避免错误的原因,因为不会发生 Ruby 对 nil 的初始化。

    以下示例证明了这一点:

    示例 #1

    def foo(bar)
      puts "foo bar: #{bar.class}"
    end
    bar = foo(bar) # => nil
    puts "bar: #{bar.class}"
    
    # Outputs: 
    #     foo bar: NilClass 
    #     bar: bar: NilClass 
    

    示例 #2

    a = a # => nil
    puts "a: #{a.class}"
    
    # Outputs: 
    #    a: NilClass
    

    示例 #3

    a = 123 if a # => nil
    puts "a: #{a.class}"
    
    # Outputs: 
    #    a: NilClass
    

    参考资料:

    Why is a = a nil in Ruby?

    Ruby 解释器在看到一个 分配给它。它在执行之前初始化局部变量 赋值表达式,甚至当赋值不可访问时 (如下例所示)。这意味着您的代码用 nil 初始化 然后表达式 a = nil 将计算为右手边的值。

    a = 1 如果为假 a.nil? # => true 第一个赋值表达式不是 已执行,但 a 被初始化为 nil。

    Ruby: method inexplicably overwritten and set to nil

    这是另一个例子:

    a = 123 if a # => nil a # => nil 我们不能说如果 a 因为我们从未设置过 a,但是 Ruby 看到 a = 123 并初始化 a, then get to if a 在哪一点 a 是 nil

    我认为这是解释器的一个怪癖,真的。加里·伯恩哈特 在 wat 取笑它 (https://www.destroyallsoftware.com/talks/wat) 用一个=一个

    【讨论】:

      【解决方案3】:

      虽然我无法回答为什么您的 params 对象会被提供的代码覆盖,但这里有一些想法。

      class AccountController < ApplicationController
        before_filter :retrieve_id_if_missing, only: :edit
      
        def edit
          # You'll find params[:id] prepopulated if it comes here,
          # else the request has been redirect
        end
      
      protected
      
        # There should be no need to pass the params object around, it should be accessible everywhere
        def retrieve_id_if_missing
          if logged_in?
            params[:id] ||= current_user.id # conditional assignment will only happen if params[:id] is nil
          end
      
          # Redirect to root if params[:id] is still blank, 
          # i.e. user is not logged in and :id was not provided through route
          if params[:id].blank?
            flash[:alert] = 'You need to be logged in to access this resource.'
            return redirect_to root_url # early return!
          end
        end
      end
      

      【讨论】:

        猜你喜欢
        • 2019-04-10
        • 2018-07-03
        • 2017-04-08
        • 1970-01-01
        • 1970-01-01
        • 2013-11-10
        • 1970-01-01
        • 1970-01-01
        • 2013-10-07
        相关资源
        最近更新 更多