3

I am a complete newbie to the world of RoR.

Although I have generated some code using rails scaffold. I am also able to post a form via ajax using the :remote => true.

And the form gets posted, nice and clean! But I wish to render some data that was returned from my controller using link_to so that it creates a link to a route/resource.

I have tried creating a .js.erb file and embedding the code in it, but it gives me an error saying:

undefined method `link_to'

code in .js.erb

$(document).ready(function(){


$("#new_post").bind('ajax:success', function(xhr, data, status){ 
    console.log(data)
    if(data.errors){
        console.log("Error!")
    }
    else{
        var user_name = data.user; // json is contained in data variable        
        $("#recent_posts").prepend("<%= j link_to(user_name, '#') %>");
    }
});

});

Where am I going wrong?

4
  • Could you include your .js.erb file's code? Commented Apr 12, 2013 at 11:07
  • After this is resolved, you may want to put the Ruby code in quotes, as to not break your .prepend() Commented Apr 12, 2013 at 11:20
  • What is the path to your .js.erb file? If it's not in app/views/_controller_name_ you may not be in a scope with access to the view helper methods like link_to. To test whether this is the case, try explicitly calling the scope by replacing link_to with ActionController::Base.helpers.link_to Commented Apr 12, 2013 at 14:01
  • I tried doing: $("#recent_posts").prepend("<%= j ActionController::Base.helpers.link_to('test', '#') %>") But didn't work! Commented Apr 12, 2013 at 14:19

1 Answer 1

1

I think there are several sources of errors here:

undefined method `link_to'

This is highly unusual, since link_to is a standard view helper. Are you sure the space before link_to is really a space and not some sort of other invisible char (you sometimes get those for example on OSX when you use space while holding alt). Furthermore, your js erb has to be in your controllers view namespace, but since it gets executed when you render the action, this seems to be the case.

$(document).ready(function(){

You won't need to use this in .js.erb templates, since there is no ready event fired. jQuery executes the script right away if the DOM is ready anyway, so it won't hurt (usually), it's just unnecessary.

$("#new_post").bind('ajax:success', function(xhr, data, status){

This is a bigger problem. The way you attach your handler now, it will be attached every time the form gets submitted and the server returns data. So, if there's an error, and the form gets submitted and returned a second time, you will either have the console message or the anchor insertion executed two times. So better be ready for this kind of event:

$("#new_post").not('.registered').addClass('registered').bind('ajax:success', function(xhr, data, status){

This will prevent multiple event handlers.

Then there's the third problem:

var user_name = data.user; // json is contained in data variable        
$("#recent_posts").prepend("<%= j link_to(user_name, '#') %>");

Here, you're trying to use a variable you assigned in javascript in the erb inline ruby. This won't work, since the ruby variable user_name is evaluated serverside when the template is rendered. The javascript variable assignment on the other hand is evaluated in the browser when the client receives the rendered template from the server. So, what can you do?

link_to is not all that magic. It just renders an anchor tag. So, the same can be written like this:

var user_name = data.user; // json is contained in data variable        
$("#recent_posts").prepend(["<a href='#'>", user_name, "</a>"].join(''));

So far, so good. The biggest problem you have though is: The server can not return both a rendered .js.erb template and json data at once. So the data you get in your javascript function will just be the rendered .js.erb template string. Communication with the server in JSON is really the best thing, so let's forget about the rails integrated form handling and write it ourselves:

  1. Delete :remote => true from the form options

  2. Add :format => :json to your create route

    resources :posts, :only => [:create], :format => :json
    resources :posts, :except => [:create]
    
  3. Add javascript in your assets that handles your form remotely

    // after DOM ready
    
    var form = $('#new_post');
    form.on('submit', function(e) {
    
      $.ajax({
        url: form.prop('action'),
        type: form.prop('method') || 'POST' //for create action,
        data: form.serializeArray(),
        dataType: form.data('type') || 'json',
        success: function(data, status, xhr) {
              var user_name = data.user; // json is contained in data variable        
              $("#recent_posts").prepend(["<a href='#'>", user_name, "</a>"].join(''));
        },
        error: function(xhr, status, error) {
          console.log('error')
        }
      });
    
      return false; //prevent normal submit
    
    });
    
  4. Now you're ready to return pure JSON from the server:

    render :json => resource.to_json(:include => :errors)
    
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. I wanted the link_to option so that I can reference it to a resource path.. Anyways your answer made even more sense. Cheers!

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.