3

Basically, I have a single page TODOAPP that is displayed in Rails on Index.html.erb and I'm trying to render the instantiated TODO objects through index.js.erb because they have a form attached to each of them that needs an authenticity token from a rails helper. Rendering the TODOs through/in Javascript is a necessity.

My solution was to try and append the todos to the Index.html.erb View through setting render "index.js.erb" in the index and calling a partial that would render then in ruby and then run ('<%= j render 'index.html.erb' %>). However, that expects an _index partial, and just trying to append or even run anything directly in index.js.erb actually results in that page itself being rendered.

Of course, I understand this is a routing issue, but I can't find anyway to render the TODO objects to the DOM through/in JS and include the authenticity token in the form they're wrapped in, since appending a form in the dom through jquery in the .js file won't allow for the token to be included.

I'd really appreciate any possible insight you might have because I've exhausted online searches and YouTube video at this point. My index controller action is:

def index
  @todo = Todo.new
  @todos = Todo.all
  respond_to do |format|
    format.html { render 'index.js.erb' }
    format.json { render :json => @todos  }
    format.js { render 'form.js.erb' }
  end
end   

And the GITHUB Repo is: https://github.com/jwolfe890/todoapp/blob/master/app/assets/javascripts/todo.js

Thank you immensely for any insight!

Dog
  • 2,726
  • 7
  • 29
  • 66

2 Answers2

3

I found a way to take the authenticity token from the layout header from this post POST request done with Authenticity Token, but exception still rased, but the routing and rendering from on js.erb is still not working.

Dog
  • 2,726
  • 7
  • 29
  • 66
2

Instead telling what to render in the html format, you could leave it to render you view as normally, this way, the index.js.erb would be rendered as "normally", and the json format would have your @todos, like:

def index
  @todo = Todo.new
  @todos = Todo.all
  respond_to do |format|
    format.html {  }
    format.json { render json: @todos  }
    format.js   {  }
  end
end

And in order to regenerate the token every time you make a request you can use an after_action callback, like:

after_action :add_csrf_token_to_json_requests

private

def add_csrf_token_to_json_requests
  if request.xhr? && !request.get? && protect_against_forgery?
    response.headers['X-CSRF-Token'] = form_authenticity_token
  end
end

And in your application.js set the csrf-token everytime the ajax request has been completed:

$(document).ajaxComplete(function(event, xhr,settings) {
  header_token = xhr.getResponseHeader('X-CSRF-Token');
  if (header_token) $('meta[name=csrf-token]').attr('content', header_token)
});
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
  • i tried that initially and it works for the AJAX call to Index, but I need a way to append those objects (or rails objects) to the DOM partially through ERB because that's the only way that would allow me to automatically generate the authenticity token. I think I have a viable workaround through the layout meta-tag, but I can't get index.js.erb to run in addition to .html.erb – Dog Aug 12 '17 at 02:37
  • Where are you facing the problem with the token?, I tried creating and editing the todo and it worked, the only one thing didn't work was the PUT request. – Sebastián Palma Aug 12 '17 at 02:39
  • For the put basically. Because it I'm going to add like a strike through function to the TODOs and put requests will need to be made. – Dog Aug 12 '17 at 02:41
  • it functionally works, but the token doesn't show up in the params, so i'm worried about security issues or bugs later – Dog Aug 12 '17 at 02:43
  • What does the `$(document).on("click", ".toggle", function(e) { ... }` line do? That line isn't working, I had to tweak it a little bit. – Sebastián Palma Aug 12 '17 at 02:52
  • sorry, yeah, that's the function i'm currently working on right now. that's going to be the event listener for a put request that will be made to change the "complete" attribute on the Todo model to true or false, resulting in a strike through being added to the object on the index page – Dog Aug 12 '17 at 02:54
  • What about this way, does it work the way you need? `$(document).on("click", ".toggle", function(e) { e.preventDefault() $.ajax({ type: 'PUT', url: `/todos/${e.target.value}` }) })` and `def update todo = Todo.find(params[:id]) todo.update(complete: !todo.complete?) end` – Sebastián Palma Aug 12 '17 at 03:08
  • won't not having an authenticity token cause security issues? – Dog Aug 12 '17 at 03:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/151759/discussion-between-sebastian-palma-and-dog). – Sebastián Palma Aug 12 '17 at 03:28