Search code examples
ruby-on-railsformsruby-on-rails-4liquidcsrf-protection

Rails Form block in helper - How do i include "Protect from forgery"


I'm trying to build a form block for my liquid theme language. I have based my approach on this answer. How ever the answer seems to be incomplete.

The problem is that protect from forgery and some other methods are unavailable. Causing an error:

Liquid error: undefined method `protect_against_forgery?' for #

This is my code:

   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)

Does any one know how i add the protect_against_forgery method do this class?

Edit: this is the error output: enter image description here

Edit 2:

This is the relevant part of my Liquid code:

{% 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 %}

Solution

  • I agree to Rodrigo but it will be hard to identify method names that will be deleagated to controller.

    That's why I prefer to extend Liquid::Block class and delegate missing methods to controller if responds..

    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