9

I'm trying to call a javascript function (actually coffeescript) from a controller in a Rails 3.2 app.

I'm getting a Render and/or redirect were called multiple times in this action error.

My code looks like this:

#Model.controller

def index
  @models = Model.all
  my_action if current_user.name == "Bob" #or some other general conditional
  ...and some stuff
  respond_to do |format|
    format.html
    format.js #this is needed to handle ajaxified pagination
  end
end

def my_action
  respond_to do |format|
    format.js { render :js => "my_function();" } #this is the second time format.js has been called in this controller! 
  end
end


#functions.js.coffee.erb

window.my_function = ->
  i = xy
  return something_amazing

What is the correct way to call a js function from the controller?

3
  • 1
    I think in coffee you need to declare a function like my_function -> (check this: js2coffee.org and try your coffee script, it does not work) Commented May 22, 2013 at 17:00
  • good spot, that one is a transcription mistake Commented May 22, 2013 at 17:09
  • I don't think my_function will be available as it isn't bound to the window or in the global namespace. See stackoverflow.com/questions/4214731/… and stackoverflow.com/questions/9059475/… Commented May 22, 2013 at 17:22

1 Answer 1

14

Man, you missed argument for block. Primary mistake.

def my_action
  #respond_to do # This line should be
  respond_to do |format|
    format.js { render :js => "my_function();" }
  end
end

And MrYoshiji's point is right. But your error was on server side, had not reached client side yet.

For the style, I think that's okay if the js code is one function call only. If more JS code, it's better to render js template

 # controller
 format.js

 # app/views/my_controller/my_action.js.erb
 my_function();
 // and some more functions.

Update: How to fix double rendering problem

You must have your #index return if condition met, or the method will continue to execute and cause rendering twice or more. Fix it like this:

def index
  @models = Model.all
  if current_user.name == "Bob"
    return my_action
  else
    # ...and some stuff
    respond_to do |format|
      format.html
      format.js #this is needed to handle ajaxified pagination
  end
end
Sign up to request clarification or add additional context in comments.

7 Comments

faceplant, good point. I've been playing with this too long! Problem not is that I have two blocks calling render (one in index, one in my-action) and this is throwing errors.
Thanks, this helps a lot and I think we're getting close to a solution. But I'm unable to resolve this Render and/or redirect were called multiple times errors. I've updated my question to provide more detail. Appreciate any ideas you may have
Thanks Billy, appreciate your quick response, and I apologize for maybe stupid questions while I try to understand this. I understand your solution above, but what if I want to add my_action to the functions already running on the page, not replace. For example, the javascript my_action function renders a popup only for Bob, but the rest of the page should still be rendered below this, not replaced. Thanks for helping me get to grips with this
@AndyHarvey, I see your points. If you want to do this, controller action is not right solution. You can simply use template to do that: <% if current_user.name == "bob" %> <%= javascript_tag bla blah %>. This is much easier and makes sense.
hm yes, i thought of this but decided against it because it seems to go against the way javascript is handled in the asset pipeline, with all js loaded simultaneously. Perhaps I need to look at this again. So this is the way you would approach this? A js file that is not included in the application.js manifest, and a specific call to that js file in the view? It seems a bit clunky, surprised Rails doesn't have a "cleaner" way to handle this.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.