escape_javascript not rendering params correctly (ajax, javascript)

Hi everyone,

In my app, users have the ability to favorite items (“listings”). To make it a smooth user experience, I’m handling the favoriting through ajax. The only problem is that the ajax isn’t rendering correctly.

The html.erb related to the favorite button is the following:

<div class="favorite-btn"><%= link_to "Save to Favorites", favorites_path(id: listing.id), method: :post, remote: true, class: "btn btn-danger btn-xs"  %></div>

I created a create.js.erb with the following and similar code in a destory.js.erb that replaces the “Remove as Favorite” with “Save to Favorites”:

$("#listing_<%= @listing.id %> .favorite-btn").html("<%= escape_javascript(link_to 'Remove as Favorite', listing_path(:id=> listing.id), method: :delete, remote: true, class: 'btn btn-danger btn-xs' )%>");

Upon the successful create action, the above javascript is run. The intended effect is that the “Save to Favorite” button is replaced by the “Remove as Favorite” code. The only problem is that the rendered via javascript code doesn’t link to the proper link and not surprisingly doesn’t work. Upon page load, the favorite path works and links to “/favorites?=id=33333”. After clicking the favorite button, the button no longer correctly removes the item as a favorite and it appears to fail because the url is not correct.

Any thoughts on where I’m going wrong with this?

Hi @realDLee,

There are a couple of things I notice. The first is that in the javascript selector you use an instance variable @listing and then in the link_to you use a local variable, listing. I’m guessing you want the instance variable.

Next, instead of listing_path(:id=> listing.id) please try listing_path(@listing)

Finally, this isn’t your problem, but there is a view helper you can use that will output the listing_<%= @listing.id %> for you. it is dom_id you can read more about it here. So using this method you would do

$("#<%= dom_id(@listing) %> .favorite-btn")

I hope that helps, let me know how it works out and if you have any further trouble with this.

thanks,
-Chad

Ok awesome. I completely forgot about dom_id.

The reason that I was using @listing in one place and just listing in another is that the favorite_button html was extracted into a view partial ( render "favorite_button", listing: @listing).

I’m a little hung up on modifying the params. It works fine for the destroy method because the natural Rails route for a delete action is /favorites/:id(.:format), which expects an id to be passed in the params. With the create action, the natural Rails route is /favorites(.:format). As a result, I was passing the id as I was as id: listing.id

Maybe this has to do with how I setup the models/controllers? In the create action,

   def create
        
    @listing = Listing.find(params[:id])
        if current_user.user_favorite_listings << @listing
    .....
  end

It looks like Chad’s suggestion on modifying the delete path was the right solution and it now works as expected.

My only remaining question on this is whether the way I am passing the id params through the create action is the proper way to handle this case. Thanks everyone!

@realDLee I overlooked what you were actually creating, which was a favorite.

The favorites route should be nested under listing.

resources :listings do
  resources :favorites
end

This will give you a route like this:

listing_favorites_path(@listing)

Then, in the favorites controller you will get params[:listing_id] as the id of the listing that the user is creating the favorite for.

thanks,
-Chad