link_to no route matches only after AJAX create of a post - javascript

Basically every time I create a post with AJAX, it won't render the new post because of this line:
<%= link_to "promote", vote_scribble_path(:scribble_id => scribble.id, :vote => true), remote: true, method: :post%>
THE LINK ABOVE ACTUALLY WORKS, it just prevents ajax render of newly created post.
here is the error that i get when trying to create new post with AJAX, it does actually create the post and it would render new post without the line above. After refresh of a page the new post with a working link appear.
Rendered scribbles/_scribbles.html.erb (18.9ms)
Rendered scribbles/create.js.erb (19.7ms)
Completed 500 Internal Server Error in 48ms
ActionController::RoutingError - No route matches {:action=>"vote", :controller=>"scribbles", :scribble_id=>155, :vote=>true}:
Here is the full code in action:
create.js.erb updates posts list after create
/*Replace the html of the div post_lists with the updated new one*/
$("#posts_list").html("<%= escape_javascript( render(:partial => "scribbles/scribbles") ) %>");
feedlist.html does render all of the posts
<div id="posts_list">
<%=render :partial => 'scribbles/scribbles', :locals => {:scribbles => #scribbles}%>
</div>
scribbles/_scribbles.html that link_to single line prevents ajax render. but it works.
<% #scribbles.each do |scribble| %>
<%= link_to "promote", vote_scribble_path(:scribble_id => scribble.id, :vote => true), remote: true, method: :post%>
<%end%>
even something like this gives me an error
<%= link_to "promote", vote_scribble_path()%>
vote_scribble_path(:scribble_id => scribble.id, :vote => true), remote: true, method: :post, :put,:get %> tried them all still same error
THE LINK WORKS IT JUST DOESN'T RENDER after AJAX CREATE, after page refresh everything is fine. any ideas why ?
resources :scribbles do
member do
post 'vote'
end
end
scribble_controller.rb
def vote
#scribble = Scribble.find(params[:scribble_id])
#vote = params[:vote]
if #vote == "true"
#v = :up
current_user.vote(#scribble, :direction => #v)
else
current_user.unvote_for(#scribble)
end
respond_to do |format|
format.js{}
end
end

You should be passing id instead of scribble_id in your link.
<%= link_to "promote", vote_scribble_path(:id => scribble.id, :vote => true), remote: true, method: :post%>
because as per your defined routes, the generated route for vote action would be:
vote_scribble POST /scribbles/:id/vote(.:format) scribbles#vote
which you can check by running rake routes.
As you can see vote_scribble_path is expecting an id placeholder and not a scribble_id which is why you receive the error as Rails cannot find a matching route in your application for scribbles#vote action with placeholder :scribble_id.

Related

Rails/Javascript: Data attribute not returned through partial, but present in DOM

I am trying to display the value of a select field for shipping costs beneath the field. Thanks to #Vasfed I am tying to use data attributes and javascript. But while the data attribute is rendered in the DOM while loading th page it is not returned in the data returned for the AJAX call when inspecting console or resources.
In DOM:
<select id="shippingservices_select" name="cart[shippingservice_id]"><option value="">select a carrier</option>
<option value="7" data-price="3.9">UPS</option>
<option value="19" data-price="10.0">DHL</option>
</select>
The fetched partial:
$("#shippingservices_select").empty()
.append("<option value=\"7\">UPS<\/option><option value=\"19\">DHL<\/option>");
I am using the following ajax call:
$(document).on("change", "#lands_select", function(event){
jQuery.ajax({
url: "/carts/update_shipping/" + event.target.value,
type: "GET",
error: function (xhr, status, error) {
console.error('AJAX Error: ' + status + error);
},
success: function (response) {
console.log(response);
}
});
});
Which should return both value and data attribute, for the form:
<%= form_for :cart, :url => {:action => "show_shipping"}, :html => { :method => "get", :remote => true } do |f| %>
<%= f.collection_select(:land_id, Land.all, :id, :name, {:prompt => "select a country"}, {:id => 'lands_select'}) %><br>
<%= f.select(:shippingservice_id, options_for_select(#shippingservices.collect { |s| [s.name.titleize, s.id, {'data-price' => s.price}] }), {:prompt => "select a carrier"}, {:id => 'shippingservices_select'}) %><br>
<% end %>
Shipping: €<div id="shipping_cost"></div><br>
with the update_shipping.js.erb view:
$("#shippingservices_select").empty()
.append("<%= escape_javascript(render(:partial => #shippingservices)) %>");
and the rendered partial _shippingservice.html.erb of:
<option value="<%= shippingservice.id %>" data-price="<%= shippingservice.price %>"><%= shippingservice.name.titleize %></option>
In the controller I have:
def update_shipping
...
respond_to do |format|
format.js
end
end
Following my partial _shippingservice.html.erb I should get both value and data attribute, but I do not. I think this is the reason why:
$(document).on("change", "#shippingservices_select", function(event){
var price = $(event.target).data('price');
$("#shipping_cost").html(price);
});
Does not return the value of data-price.
How can I get this to work? Thank you in advance.
UPDATE
I was trying to troubleshoot it and things appear to be quite strange.
Both selectors display data in the DOM. The shipping service select field which get’s loaded on page load shows everything. On changing the land selector, the partial which gets loaded and which I can inspect in console does only display option value + name, but when changing the _shippingservice partial I found out that the code which gets loaded through AJAX appears not to be generated by the partial referenced in the JS Ajax call, since I can change the code inside without producing any effect on the delivered payload.
But when substituting
<%= escape_javascript(render(:partial => #shippingservices))%>
By
<%= escape_javascript(render ‘carts/shippingservice’)%>
Nothing is displayed and loaded.
You can check what partials are getting rendered on the terminal where you are running rails. Looks like you have more than 1 possible partial for shipping services.
You can also specify which partial to use instead of letting rails guess:
render partial: 'carts/shippingservice', collection: #shippingservices, as: :shippingservice

How to implement Ajax in Rails?

Webpage Look
So I have a Todo List and contains Todo Items. And for each incomplete task(item), there is a button next to it called "Mark Item as Done". (See button_to method) Whenever I click on that button, it should go into that item and mark it as done. However, I'm struggling to implement AJAX into this project and I need help. I'm new to rails and ajax, so I have no clue what I'm doing... The alert message in the update.js.erb is to test if it's reaching there.
Am I supposed to create a partial file called _todoitems.html.erb or _todolists.html.erb? And what else am I missing and what else do I need to do?
Here are the relevant files of what I've done so far...
routes.rb
todolist_todoitems GET /todolists/:todolist_id/todoitems(.:format) todoitems#index
POST /todolists/:todolist_id/todoitems(.:format) todoitems#create
new_todolist_todoitem GET /todolists/:todolist_id/todoitems/new(.:format) todoitems#new
edit_todolist_todoitem GET /todolists/:todolist_id/todoitems/:id/edit(.:format) todoitems#edit
todolist_todoitem GET /todolists/:todolist_id/todoitems/:id(.:format) todoitems#show
PATCH /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
PUT /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
DELETE /todolists/:todolist_id/todoitems/:id(.:format) todoitems#destroy
todolists GET /todolists(.:format) todolists#index
POST /todolists(.:format) todolists#create
new_todolist GET /todolists/new(.:format) todolists#new
edit_todolist GET /todolists/:id/edit(.:format) todolists#edit
todolist GET /todolists/:id(.:format) todolists#show
PATCH /todolists/:id(.:format) todolists#update
PUT /todolists/:id(.:format) todolists#update
DELETE /todolists/:id(.:format) todolists#destroy
root GET / todolists#index
todolists/_form.html.erb
<%= form_for(#todolist, remote: true) do |f| %>
todolists_controller.rb
# PATCH/PUT /todolists/1
# PATCH/PUT /todolists/1.json
def update
respond_to do |format|
if #todolist.update(todolist_params)
format.html { redirect_to #todolist, notice: 'Todolist was successfully updated.' }
format.json { render :show, status: :ok, location: #todolist }
format.js
else
format.html { render :edit }
format.json { render json: #todolist.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todolist
#todolist = current_user.todolists.find(params[:id])
end
todolists/show.html.erb
<!-- paginate_items is basically the current user's items -->
<% #paginate_items.each do |item| %>
<div class="list">
<% if item.due_date > Date.today %>
<% if item.done? %>
<a class="complete">
<%= item.due_date %>
</a>
<a class="linkResults">
<%= link_to "#{item.task_title}", [#todolist, item], style: "font-weight: bold;" %><br/> <br/>
</a>
<% else %>
<form class="oneLine">
<a class="notDue">
<%= item.due_date %>
</a>
<a class="linkResults">
<%= link_to "#{item.task_title}", [#todolist, item], style: "font-weight: bold;" %>
<%= button_to "Mark Item as Done", edit_todolist_todoitem_path(#todolist, item), remote: true, id: "done_item_true" %><br/> <br/>
</a>
</form>
<% end %>
todolists/update.js.erb
alert("TEST TEST TEST");
Add a custom route for the ajax request in routes.rb. If you have resources for items make it something like:
resources :items do
collection do
post 'check_it_off'
end
end
Add a corollary controller action in your items controller and update the state when that action is called:
def check_it_off
item_id = params[:item_id]
item = Item.find(item_id)
# whatever you are updating, just an example
item.status = done
item.save
render json: {data: "Success"}
end
Attach an event to marking the item off and call your ajax request:
$(document).on('click', '.some-class', function(e){
e.preventDefault();
var itemId = $('#item_id')
$.ajax({
type: 'POST',
url: '/items/check_it_off'
data: itemId
}).done(function(response){
console.log(response)
})
})
In your view, give every item an id that relates to their actual id by saying something like: id="<%= item.id %>"
That should do it. That's basically a full ajax post request.
Add some javascript to handle the response on the form and the update the dom on the success callback.
$(function(){
$("#form_id").on("ajax:success", function(e, data, status, xhr) {
// update the dom here, e.g.
$("#stuff").append('<img src="check.png"/>');
}
).on("ajax:error", function(e, xhr, status, error) {
console.log(e, xhr, status, error);
}
)
});

link_to doesnt replace div's content

the relevant controller code:
def show_host
queue = TestQueue.find(params[:id])
#test_queues = TestQueue.where(:host => queue.host)
respond_to do |format|
format.html { render action: "show_host", :layout => nil}
format.json { render json: #test_queue }
end
end
view:
<iframe name="host_queues", scrolling="yes" width="82%" height="700px", align="right", frameborder="0", rel="stylesheet"></iframe>
<%= link_to host, { :controller => "test_queues", :action => "show_host", :id => id}, {:target => "host_queues"} %>
now the thing is, it works with replace the content of the iframe, but when i try to replace content in a div with class="host_queues", it doesnt work... works only with iframe ..
can any1 out a finger on the reason ? 10x ..
target only applies to frames and windows. You have to use Javascript to replace the contents of a div.
use remote: true option in link_to and than write javascript
OR
use form_tag with remote: true, in update option, give div id which you want to replace
you can chek below link
http://guides.rubyonrails.org/working_with_javascript_in_rails.html

How to call a .js.erb file instead of a .rjs one

I'm working on a migration from Prototype to jQuery and we also have to remove .rjs file when we can. There is here one issue :
I have got the update_overall_comment.rjs file in the app/views/results folder:
page.replace 'overall_comment', :partial => 'results/marker/overall_comment', :locals => {:result => #result}
page.visual_effect(:highlight, 'overall_comment_text_area', :startcolor => '#BDFCC9')
The _overall_comment.html.erb file in the app/views/results/markers folder:
<div id="overall_comment">
<div id="overall_comment_edit">
<%= form_for #result,
:remote => true,
:url => { :action => 'update_overall_comment', :id => #result.id } do |f| %>
<%= f.text_area :overall_comment,
:cols => 50,
:rows => 5,
:id => 'overall_comment_text_area',
:onkeydown => "$('overall_comment_submit').enable();" %>
<div>
<%= f.submit t(:save_changes),
:disable_with => I18n.t('working'),
:disabled => true,
:id => "overall_comment_submit"%>
</div>
<% end %>
</div>
</div>
And the results.controller.rb file (I just show the relevant function ) in the app/controllers folder:
def update_overall_comment
#result = Result.find(params[:id])
#result.overall_comment = params[:result][:overall_comment]
#result.save
end
The fist thing I would like to understand is how to transform the .rjs file to a .js.erb on. I removed it and created update_overall_comment.js.erb (in the same folder) which only contains a console.log('...'), and I never saw the console.log called.
Do you have any ideas ?
Thank you in advance.
rename update_overall_comment.rjs to update_overall_comment.js.erb
then in this file:
$('#overall_comment').html("<%= j(render 'results/marker/overall_comment') %>");
$('#overall_comment_text_area').effect("highlight", { color: "#BDFCC9" }, 3000);
p.s. not sure about the highlight, also for verifying that the js.erb file is called/rendered, I use alert('something here'); instead of console('...');, but this shouldn't be much of a difference in order to test an ajax call.
Thank you very much. I have made some mistakes.
For instance I thought a line with "//" was a comment and in fact it does a ajax error. Also I used partial for the first line and it did't work.
And I thought this js.erb file would inform me about errors but no. It just stop when it doesn't work without any information. So I had to find by myself that my jquery version didn't have the "effect" method.
But now it works and your translation of visual_effect work (I just put 1000ms instead of 3000).

How to pass param['id'] to the index page

I am trying to render the user detail on index page when user is clicked.
I am having the list of users in index page like
<% #users.each do |user| %>
<%= link_to user.name, '', {:id => user.id, :name => 'user', :remote => true}
<% end %>
In my javascript
$('#mydiv').html("<%= escape_javascript(render(:partial => '/users/show', :locals => {:id => #{params['id']}})) %>"
but I couldn't able to render the user details, because param 'id' is not passing to this page.
How to get this param and render the partial in the index page when user is clicked.
In this case you should review your code a little. You should directly call the show method in your link and edit your controller to have it responding to JavaScript:
View code:
<%= link_to user.name, user_path(user), remote: true %>
Controller code:
def show
#user = User.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
And create a new view called users/show.js.erb
$("#mydiv").html("<%= escape_javascript(render(:partial => '/users/user_show', :locals => {:user => #user})) %>");
This view is calling a partial view where you can render all your user data. This view is called users/_user_show.html.erb
<div class="myuser">
<%= user.name %>
</div>
Hope that helps

Categories