Authenticity Token being created differently when using render_to_string

526 Views Asked by At

I'm generating a small form through render_to_string and for some reason the CSRF token is not being generated correctly (i.e. it's different from the header and the user is logged out on submit, along with a "Can't verify CSRF token" on the logs). Here's the relevant code:

Controller:

def publish
  @question = @event.questions.find(params[:id])
  @question.update_attribute(:published, true) unless @question.published?
  Pusher[@event.to_param].trigger('new_question', question: render_question)
  redirect_to event_path(@event)
end


private
  def render_question
    render_to_string('questions/_unanswered_question', locals: {question: @question}, layout: false)
  end
  def fetch_event
    @event ||= current_user.events.find(params[:event_id])
  end

I'm using Pusher, but you can assume this is just being rendered on the page with this Javascript:

$("#questions").append(data.question); // data is what I send from Pusher.

And finally, the partial being rendered:

.answer
  = form_for [@event, question, question.answers.new] do |f|
    %h2
      = question.title

    %ul
      - (1..5).each do |n|
        - if question.send("answer_#{n}").present?
          %li
            = f.radio_button :option, n, id: "q_#{question.id}_answer_option_#{n}"
            = f.label question.send("answer_#{n}"), for: "q_#{question.id}_answer_option_#{n}"

    %p
      = f.submit "Answer"

This works just fine without being appended to the page, but rendered within the layout. Note that this is not a remote form.

1

There are 1 best solutions below

0
Paul Spieker On

It looks like you are generating the form using ajax and then adding it to the Dom. The csrf token is generated new for every request. As far as I know, you have to use the csrf token which is available in the header and replace the one in the form with it using js.

Should look something like this:

success: ()->
  parameter = $("meta[name=csrf-param]").attr("content")
  token     = $("meta[name=csrf-token]").attr("content")
  question  = $(data.question).find("[name="+parameter+"]").val(token)

Currently I have no computer to test that first, so hopefully I am right :/