I'm working on a Ruby on Rails aplicattion, my problem is that I have all the comments of a post paginated and showed perfectly, but when an user saves a new comment via ajax, and I replace all the content with the partial with the new content(including the will_paginate #comments), the urls of the links change to the url of the action that saves the comments and i don't know how to do to make them link correctly.
I tried with <%= will_paginate #comments, :params => {:controller => 'posts', :action => 'show_outside_comments' %>
But I get the same results.
Thank you very much for your help!
Have you looked into the ajax methods described here?
http://railscasts.com/episodes/174-pagination-with-ajax
you can execute javascript code to update the links,
something like:
<div class="paging_links" >
<%= will_paginate #comments, :params => {:controller => 'posts', :action => 'show_outside_comments' %>
</div>
<script type="text/javascript">
jQuery('.paging_links a').click(function(event){
href = jQuery(this).attr('href');
event.preventDefault();
// update href here
})
</script>
$('.pagination a').attr('href', function() {
$(this).prop('href').replace('/comments', location.pathname);
});
Assuming you want to replace `/comments' with the current pathname.
Related
I have a controller "mainpage", with a correspondingly named view. The controller creates a #myLocalSuites variable, and the view includes the following line:
<li class="active"><%= link_to "Perforce", :action => 'renderp4', :remote => true, :localSuites => #myLocalSuites %></a></li>
Routing is defined such that clicking this link_to calls renderp4.js.erb to render a partial within the mainpage view:
$('#MainPage').replaceWith('<%= escape_javascript render "perforce_sync/perforceSync" %>')
where _perforceSync partial includes:
<%= select_tag "perforceSuites", options_for_select(*MYOPTIONSVARIABLE*), {:class => 'form-control', :size => "20", :multiple => true} %>
Where *MYOPTIONSVARIABLE* needs to be myLocalSuites as cascaded down from the mainpage view/controller.
Having tried everything I can think of, and failed - can someone please show how to modify the above snippets to use the required variable in the PerforceSync partial? Everything I've tried seems to produce something along the lines of:
ActionView::Template::Error (undefined method `map' for nil:NilClass):
An example of what I've tried. I don't think I'm a million miles off, but...
<li class="active"><%= link_to "Perforce", :action => 'renderp4', :remote => true, :localSuites => #myLocalSuites %></a></li>
$('#MainPage').replaceWith('<%= escape_javascript render "perforce_sync/perforceSync", :suitesLocally => params[:localSuites]%>')
<%= select_tag "perforceSuites", options_for_select(params[:suitesLocally]), {:class => 'form-control', :size => "20", :multiple => true} %>
Thanks! :)
In response to your comment, there are two things you can do here. One way is to simply render some dynamic JS on page load, and then use javascript to show that data at a later point.
If this data however is to depend on user actions after the page has loaded, you must make another request to the server using AJAX.
The first way might look like this:
<script>
var my_data = "<%= #some_data %>";
//#some_data could be set by the controller action for example
$('button').click(function() {
$('div.content_container').text(my_data);
});
</script>
The second way would look like this:
<script>
$('button').click(function() {
$.ajax({
url: '/some_resource/id.json',
data: {param1: 'some_user_data'}
}).done(function(data) {
$('div.content_container').text(data);
});
});
</script>
The data option for the ajax call allows you to pass parameters back to the server, so you can send some data provided by the client. Documentation for jquery ajax is here if you want to see other options.
The .done callback gets fired when the client receives a response from the server, and the function parameter is the data returned.
I am using HAML based templates and pagination seems to be broken for me with Kaminari. I'm sure it's my fault but here's what my template looks like:
:javascript
$(function() {
$('#events').html('<%= escape_javascript render(#events) %>');
$('#paginator').html('<%= escape_javascript(paginate(#events, :remote => true).to_s) %>');
});
%ul.activity_list
#events
= render :partial => 'event'
my _event.html.haml looks like:
- #events.each do |event|
= display_event(event)
And finally:
%nav
%ul.pagination
#paginator
= paginate #events, :remote => true
What happens now when I load the page is where the paginated events should be I literally see the following markup:
<%= escape_javascript render(#events) %gt;
And it renders on the site as:
<%= escape_javascript render(#events) %>
What am I doing wrong here to get XHR enabled pagination here?
UPDATE
I've updated my javascript to the following as per Dylan's request:
:javascript
$(function() {
$('#events').html('#{escape_javascript render('event')}');
$('#paginator').html('#{escape_javascript(paginate(#events, :remote => true).to_s)}');
});
It seems XHR is working, but for some reason, it will never go past page=2. This particular fetch should have 3 pages total and it'll only flip between pages 1 and 2. Any reason for this?
You're trying to use erb tags in a haml file. You should be using haml's version of interpolating ruby code (#{} instead of <%= %>):
:javascript
$(function() {
$('#events').html('#{escape_javascript render(#events)}');
$('#paginator').html('#{escape_javascript(paginate(#events, :remote => true).to_s)}');
});
See the Haml documentation about this
I am new to Ruby on Rails and i am working through a few example applications in the O'Reilly Head First Rails book. In one of the examples there is a page made up of three partials. The middle partial is a list of items. There is a link right below this section that, when clicked, should refresh the div containing that partial. The book is running examples based off of Rails 2.3 i believe and i am using Rails 3.1. This is the example that the book is giving me:
routes.rb:
map.connect '/flights/:flight_id/seats', :action=>'flight_seats', :controller=>'seats'
seats_controller.rb:
def flight_seats
#flight = Flight.find(params[:flight_id])
render :partial => "flights/seat_list", :locals => {:seats => #flight.seats}
end
show.html.erb:
<div id="seats">
<%= render :partial=>"seat_list". :locals=>{:seats=>#flight.seats} %>
</div>
<$= link_to_remote("Refresh Seats", :url=>"/flights/#{#flight.id}/seats", method=>"get", :update=>"seats") %>
This example is also using prototype.js since that's what Rails 2.3 came with built in. Rails 3 has jQuery as the default JavaScript library. (not sure if that makes a big difference)
Here is what i have so far. This is getting the contents of the partial correctly, it's just not updating the "seats" div after the AJAX call gets the partial. My code:
routes.rb:
match 'flights/:flight_id/seats' => 'seats#flights_seats'
seats_controller.rb:
def flights_seats
#flight = Flight.find(params[:flight_id])
render :partial => "flights/seat_list", :locals => { :seats => #flight.seats }
end
show.html.erb:
<div id="seats">
<%= render :partial => 'seat_list', :locals => { :seats => #flight.seats } %>
</div>
<%= link_to "Refresh Seats", "/flights/#{#flight.id}/seats", :remote => true %>
Any idea why my <div id="seats"> won't refresh with the updated partial? I'm betting there is but i'll ask anyway, is something wrong with my code?
The :remote => true option is a bit weird if you aren't returning JSON data. You can wrap your HTML in a JSON object, though, which is what I typically do. Or if you want something closer to your existing code something like this should work for you:
<%= link_to "Refresh Seats", "/flights/#{#flight.id}/seats", :class => "refresh-seats" %>
In your javascript somewhere:
$(document).delegate(".refresh-seats", "click", function(e){
e.preventDefault();
$("#seats").load(this.href);
});
How can I easily pass the value I get from the auto_complete textfield to a partial.
<%= text_field_with_auto_complete :participant, :name, {}, {:url => {:controller => "contentcom/discussions", :action => :get_users_for_auto_complete}, :method => :get, :param_name => 'search'} %>
<%= button_to_function(:OK) do |page|
page.insert_html :top, :participants, :partial => 'participant', :locals => end %>
Bye,
Nico
First of all you need to know that the helpers text_field_with_auto_complete and button_to_function not really handle user actions, but only generate HTML and javascript code. Only generated javascript code can interact with the user. In this case text_field_with_auto_complete generates the following (approximately):
<input type="text" id="participant_name" name="participant[name]" size="15" />
<div id="participant_name_auto_complete" class="auto_complete"> </div>
<script type="text/javascript">
var participant_auto_completer = new Ajax.Autocompleter (
'Participant',
'Name',
'/contentcom/discussions/get_users_for_auto_complete',
{method: 'GET', param_name: 'search'}
);
</script>
The above code is that the user gets in his browser.
If you read the documentation for text_field_with_auto_complete, then you will see that we can use the option :after_update_element. This option allows us to specify the name of the JavaScript function that will be called when the user selects one of the proposed values.
What we need to do:
write a JavaScript function that
will display anywhere user-selected
value from autocomplete field.
call text_field_with_auto_complete
with :after_update_element
That's how the template will look like:
<ul id="selected_participant_container"></ul>
<%= text_field_with_auto_complete :participant, :name, {}, {
:url => {:controller => "contentcom/discussions", :action => :get_users_for_auto_complete},
:method => :get,
:param_name => 'search',
:after_update_element => 'afterParticipantSelected'
}%>
<script type="text/javascript">
function afterParticipantSelected (el, value) {
var container = document.getElementById ('selected_participant_container');
container.innerHTML = value;
}
</ Script>
Now, when a user selects a value in the autocomplete field, it will be displayed in the element with id = selected_participant_container
Of course, you can use methods that are proposed by tokland.
But I would Recommend you first learn the basics of HTML and Javascript.
Note first that the block of button_to_function (and its partial, of course) is generated server-side, so it has no way to know the value of the autocomplete in the client. You have 2 ways to accomplish what you want: create a RJS action for the auto_complete (if that's possible) or 2) use Javascript/AJAX and connect to the auto_complete URL, get the value and modify the DOM accordingly (also in JS).
thanks for reading this post. I've been stuck on an issue with RoR for the past few days. I have a form under index.html.erb as:
<head>
<title>Ajax List Demo</title>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>
<h3>Add to list using Ajax</h3>
<% form_tag :action => :list , :method=>:get, :remote=>true do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
<div id="my_list">
</div>
</body>
In the controller I have:
def list
puts "here!!!!"
reader = Reader.new
#profiles = reader.processURL(params[:url]) #profileList =
respond_to do |format|
#format.html { render :partial=>true, :locals => { :profiles => #profiles}}#{ render :partial=>'profiles/list',:layout => false, :locals => { :profiles => #profiles}}
format.js {render :content_type => 'text/javascript', :locals => { :profiles => #profiles}}
# index.html.erb
# format.rss render :partial=>'profiles/list',:layout => false, :locals => { :profiles => #profiles}
end
And a js file for remote UJS as list.js.erb
$("#my_list").html("<%= escape_javascript(render(:partial => "list"))%>");
The issue is I cannot get the results to render the partial _list.html.erb, in the div tag my_list. I get a blank page, 406 error. If I un-comment the render html code in the controller I get the partial back rendered in the browser. I am kind of stuck, I want to submit the form and the results to pop in the my_list div. I'm new to rails so if I'm missing something obvious don't hesitate to point it out to me....I'm definitely willing to try.
Changed it to this:
<html>
<head>
<title>Ajax List Demo</title>
<h1>Listing posts</h1>
<%= javascript_include_tag 'jquery.js' %>
<%= csrf_meta_tag %>
</head>
<body>
<h3>Add to list using Ajax</h3>
<% form_tag :action => :doit , :method=>:get, :remote=>true do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
<div id="my_list">
</div>
Controller:
def doit
puts "here!!!!"
reader = Reader.new
#profiles = reader.processURL(params[:url])
respond_to do |format|
# format.html {render :partial=>true, :locals => { :profiles => #profiles}}#{ render :partial=>'profiles/list',:layout => false, :locals => { :profiles => #profiles}}
format.js #{render :content_type => 'text/javascript', :locals => { :profiles => #profiles}}
# index.html.erb
# format.rss render :partial=>'profiles/list',:layout => false, :locals => { :profiles => #profiles}
end
JS
_doit.js.erb
$("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
And finally a partial:
_doit.html.erb.
However I am still getting the 406 error, I dont have a duplicate _doit js or erb. Does anything standout as incorrect from this? Thanks again!
Another update:
I think the form is not rendered correctly:
This rendered:
<% form_tag :action => :doit , :remote=>true, :id => 'myform' do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
This:
<form accept-charset="UTF-8" action="/home/doit?id=myform&remote=true" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="MLuau4hvfdGO6FrYCzE0c0JzwHhHKZqjmV49U673sK8=" />
</div> Enter the public url:
<input id="url" name="url" size="80" type="text" value="" />
<input name="commit" type="submit" value="Find" />
<input name="commit" type="submit" value="Find" />
Its adding my remote tag and id to the query string, isnt this wrong?
Ok finally got a clue forms need to be bracketed:
<%= form_tag( { :action => 'doit' }, :multipart => true, :remote=>true, :id => 'myform' ) do %>
Ok last update tonight:
Now I get in the logs:
Started POST "/home/doit" for 127.0.0.1 at Wed Oct 27 22:40:55 -0400 2010
here!!!!
Processing by HomeController#doit as JS
Parameters: {"commit"=>"Find", "url"=>"http://www.facebook.com/people/James-Stewart/653161299", "authenticity_token"=>"MLuau4hvf
dGO6FrYCzE0c0JzwHhHKZqjmV49U673sK8=", "utf8"=>"Γ£ô"}
Rendered home/_doit.html.erb (4.0ms)
Rendered home/doit.js.erb (9.0ms)
Completed 200 OK in 807ms (Views: 40.0ms | ActiveRecord: 0.0ms)
I see as JS and it says it renders my js/partial. However I am getting nothing on my_list div. My JS file:
$("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
My html.erb form file has now:
<script$('#myform').bind('ajax:success', function(evt, data, status, xhr){
xhr.responseText;
});></script>
Its like the form does nothing, which is a good sign, no more 406 error. I know this is close, if anyone can point what I need to do in the js that would be great otherwise I'll take a break and try tmrw.
Ok I think its getting a response back just not rendering as you pointed out would be the issue yesterday Steve.
Debugging the JS on Firebug I see the html I want rendered in the div, for this:
http://localhost:3000/javascripts/prototype.js?1285674435/event/seq/1
Which means I think I am getting the JS response back now.
I have this on the form page:
<script>$('#myform').bind('ajax:success', function(evt, data, status, xhr){
$('#my_list').html(eval(xhr.responseText));
});</script>
Inspections say it doesnt know what myform is, but I put :id => 'myform' in the Rails code.
Again all thanks, I got a ton of help here and I want to share how I finally got it working back to the community.
The, js file for the method doit(def. need a better controller action name) is doit.js
The code was ultimately:
$("my_list").update("<%= escape_javascript(render(:partial => "doit"))%>");
For some reason leaving it as #my_list wouldn't be found in firefox, I had to use firebug to finally figure this out.
Obviously this is different from the way suggested below, and I am going to place the js script back into the form and remove the .js.erb file and see how that works works. I suppose I just render the partial in the format.js response? Also where does everyone find info on writing the UJS files? I know nothing about the syntax for anything starting with $.
Again thanks for the help, finally feel like I am making progress on learning rails.
I posted this answer on Hacker News, but figured the Stack Overflow community might benefit as well :-)
In Rails 3, the javascript drivers are very hands-off (i.e. unobtrusive). The problem you're having is that your app is returning to the browser a string of javascript, but there is nothing in the page that is then executing that javascript in the context of the page.
The rails.js ujs driver binds to forms and links with data-remote=true, which is what the :remote => true is doing, to make them submit their requests remotely, but that is where the Rails magic stops.
The good news is that the remote requests fires off some events you can bind to, which give you access to the data returned by the server (which fire off in the following order):
ajax:before
ajax:loading
ajax:success
ajax:complete
ajax:failure
ajax:after
You need to bind an event to the ajax:success event of your form. So, if your form had the id "myform", you'd want something like this on your page:
$('#myform').bind('ajax:success', function(evt, data, status, xhr){
eval(xhr.responseText);
});
xhr.responseText is what your server returns, so this simply executes it as javascript.
Of course, it's proper to also bind to the failure event with some error handling as well.
I usually don't even use the action.js.erb method of returning javascript, I just have my controller render the HTML partial, and then I have a binding like this in the page:
$('#myform').bind('ajax:success', function(evt, data, status, xhr){
$('#target-div').html(xhr.responseText);
});
I'm actually in the middle of writing a full article on this, but hopefully this is enough to get you going.
EDIT: I finished that article, fully explaining remote links and forms in Rails 3. Maybe it will help:
Rails 3 Remote Links and Forms:
A Definitive Guide
If you look at the rendered source of your page, you should notice an error in the fields attributes.
The correct way to do it is as follows:
<%= form_tag({:action => 'list'}, :remote => true %>
Notice the curly brackets, very important! Alternatively you could have done:
<%= form_tag('list', :remote => true %>
Do you have 2 partials named '_list'? Maybe that's causing problems and you should just a little more specific:
$("#my_list").html("<%= escape_javascript(render(:partial => "list.html.erb"))%>");
I'm not sure if this helps, but are if you using in IE be aware that IE sends some headers that screw with how your controller responds. So you may be sending an Ajax request with IE, but your Rails app thinks its just a plain html request.
I've had to setup jQuery to first erase the current headers and then add just the javascript header:
$.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept",'');xhr.setRequestHeader("Accept", "text/javascript")}
})
Using list as your function name in the controller may be the problem. That name is used internally by Rails.
Rails 5.1 introduced rails-ujs, which changes the parameters of these event handlers. The following should work:
$('#myform').bind('ajax:success', function(event) {
const [_data, _status, xhr] = event.detail;
});
Source:https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers
I know this is an old question but someone can benefit from it.
I think the error is related to this:
JS _doit.js.erb $("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
And finally a partial:
_doit.html.erb.
You are creating a _doit.js.erb partial to respond to the action doit in the controller but what you need is a view called doit.js.erb (without the underscore). Conceptually, the format.js in your action will respond to a view with the same name of it with extension js.erb.