【问题标题】:Rails Form block in helper - How do i include "Protect from forgery"帮助程序中的 Rails Form 块 - 我如何包含“防止伪造”
【发布时间】:2014-09-03 03:03:27
【问题描述】:

我正在尝试为我的液体主题语言构建一个表单块。我的方法基于this answer。答案似乎不完整。

问题是防止伪造和其他一些方法不可用。导致错误:

Liquid error: undefined method `protect_against_forgery?' for #

这是我的代码:

   class LiquidFormTag < Liquid::Block

        include ActionView::Context
        include ActionView::Helpers::FormHelper

        def initialize(tag_name, markup, tokens)

            super
        end

        def render(context)
            form_tag("#") do

                super
            end
        end
    end

    Liquid::Template.register_tag('liquid_form', LiquidFormTag)

有谁知道我如何添加protect_against_forgery 方法来做这个类?

编辑:这是错误输出:

编辑 2:

这是我的 Liquid 代码的相关部分:

{% ticket_form %}
    {% for offer in event.offers %}

        <div class="well well-sm">  
            <div class="row">
                <div class="col-xs-3 col-sm-5 col-md-6 col-lg-7">
                    <h5>{{offer.name}}</h5>
                </div>
                <div class="col-xs-9 col-sm-7 col-md-6 col-lg-5 pull-right">
                    <div class="input-group">
                        <span class="input-group-addon">{{offer.price}}</span>
                        <input type="email" class="form-control tickets-count" cols="2" id="exampleInputEmail1" placeholder="0">
                        <span class="input-group-btn">
                            <button type="button" class="btn btn-default"><i class="fa fa-plus"></i></button>
                            <button type="button" class="btn btn-default"><i class="fa fa-minus"></i></button>
                        </span>
                    </div>
                </div>
            </div>
        </div>

    {% endfor %}
{% endticket_form %}

【问题讨论】:

    标签: ruby-on-rails forms ruby-on-rails-4 liquid csrf-protection


    【解决方案1】:

    方法protect_against_forgery来自ActionController::RequestForgeryProtection模块。但是在Liquid::Block 类中包含这个模块似乎不是一个好习惯。

    我使用的解决方案是:

    class LiquidFormTag < Liquid::Block
      include ActionView::Context
      include ActionView::Helpers::FormHelper
    
      attr_reader :controller
    
      def initialize(tag_name, markup, tokens)
        super
      end
    
      def render(context)
        @controller = context.registers[:controller]
        form_tag('#') do
          super(context).html_safe
        end
      end
    
      delegate :form_authenticity_token, :request_forgery_protection_token, :protect_against_forgery?, to: :controller
    
    end
    
    Liquid::Template.register_tag 'liquid_form', LiquidFormTag
    

    要让这段代码工作,你需要为 Liquid 渲染方法提供当前控制器:

    class OffersController < ApplicationController
    
       def create
          @offer = Offer.new
          Liquid::Template.parse(template).render 'offer' => @offer, registers: {controller: self}
       end
    
    end
    

    【讨论】:

    • 不错!差不多了。现在唯一的问题是表单内容被渲染得很奇怪。输出中有 t\r\n \r\n \r\n 的分配。它说 :controller 为零。
    • 是的。但是液体块类可能会阻塞它?或者你也在液体块内使用它吗?还有什么方法可以测试 attr_reader 是否有效?
    • 请用您的表单类和液体代码更新您的答案
    • Form 类是什么意思?你的意思是例如 Offer 模型的地方吗?
    • 另请注意:我写的代码完全像你的答案,所以如果 :controller 应该是我正在为其构建类的类控制器,那么这可能是错误。
    【解决方案2】:

    我同意 Rodrigo,但很难确定将委托给控制器的方法名称。

    这就是为什么我更喜欢扩展 Liquid::Block 类并将缺少的方法委托给控制器(如果响应)..

    class LiquidFormTag < Liquid::Block
      include ActionView::Context
      include ActionView::Helpers::FormHelper
    
      attr_reader :controller
    
      def initialize(tag_name, markup, tokens)
        super
      end
    
      def render(context)
        @controller = context.registers[:controller]
        form_tag('#') do
          super(context).html_safe
        end
      end
    
    end
    
    
    Liquid::Block.class_eval do
      # This delegates missing - including private & protected - methods (like protect_against_forgery?) to controller.
      def method_missing(*args)
        begin
          if controller.respond_to?(args.first, true)
            controller.send(args.first)
          else
            super
          end
        rescue
          super
        end
      end
    end
    

    【讨论】:

      【解决方案3】:

      这几天我也遇到了同样的问题,我是这样解决的:

      class LiquidForm < Liquid::Block
        include ActionView::Context
        include ActionView::Helpers::FormHelper
      
        attr_reader :csrf_token
      
        def initialize(tag_name, markup, options)
         super
         @model = markup.strip
        end
      
        def render(context)
          csrf = context.registers[:csrf_token]
      
          form_tag "/new_obj", authenticity_token: false do
            "#{hidden_field_tag('authenticity_token', csrf)}
             #{super(context)}".html_safe
          end
      
        end
      end
      

      现在我需要从我的应用程序中生成安全令牌。我调查了在form_tag 内部我可以调用form_authenticity_token 方法,该方法可从ActionController::RequestForgeryProtection 模块获得。 Based on this answer.

      这个form_authenticity_token只创建了一个安全的随机密钥,你可以在form_authenticity_token看到它

      # File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 249
        def form_authenticity_token
          session[:_csrf_token] ||= SecureRandom.base64(32)
        end
      

      因为我们不能在 LiquidForm 类中调用它。我们需要像 Liquid 渲染方法中的这个方法一样手动生成令牌。这可以在您的视图或控制器中。示例:

      =Liquid::Template.parse(template).render('offer' => @offer, registers: {:csrf_token => session[:_csrf_token] ||= SecureRandom.base64(32)})
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        相关资源
        最近更新 更多