Ajax on Rails - I'm having an issue - ruby-on-rails

I'm working on a Ruby on Rails web app, in which I've got several lists of posts. Each post will use Ajax to load their comments. In order of populating them in the right place, I'm doing the following:
Each post has a div with an id formatted as follows: <div id="my_div_<%= post.id %>"></div>. So, for example if the post.id is 12, the id will be "my_div_12".
My controller's action looks like this:
render :update do |page|
page.replace_html 'my_div_' + params[:post_id].to_s, :partial => 'my_comments_section_partial_path'
end
That works fine only if I have a post only once at the page. But in this site, each post might be listed more than once, because there are several lists (latest posts, popular, tops, etc). And all of them will have their Comments section to show.
The issue now is that, as the comments section functionality is inside a partial view, it will work the same for every type of list (as it's expected), and therefore, it doesn't make the difference between the divs (because they will have the same post.id, and thus, the same div's id).
My question now is: how could I solv this problem? Is there a better and different way for doing this?
Thanks in advance!
EDIT:
Just to clarify what I want, in few words:
I would like the code page.replace_html 'my_div_' + params[:post_id].to_s, :partial => 'my_comments_section_partial_path' to replace that partial in EVERY div called 'my_div' + params[:post_id].to_s (because there may be more than one div in the same page with the same id).

Note that having several elements with the same id on one page produces technically invalid html. Many browsers won't even render all those id attributes (leaving one and erasing the rest).
One simple solution is to switch to using classes instead of ids. There can be multiple elements with the same class and each element can have more than one class.
I don't work with built-in ajax helpers in Rails, but google suggests it's possible.

It seems like you have two sets of posts on the same page and are worried about putting the comments for the correct post in the correct spot. I think making two Ajax requests would be fine. The URLs would probably be something like /posts/1/comments and /posts/2/comments. Essentially what you want is "all the comments for a given post". You could have a comments action on your posts controller to use your has_many :comments association from Post. Using the URL ID parameter you can supply the post ID. You could get the Post ID out of the markup through a custom ID attribute, a custom class, or a custom data-* attribute.
It looks like you're using RJS but I'd recommend using Prototype or jQuery to make the Ajax request and specify JSON data or HTML as the response, then append the JSON or HTMl in the correct spot.
In jQuery I'd grab the post ID, make the ajax request, then append the comment HTML. This is not tested, but roughly the idea in code.
var comments_div = $('.post .comments'); /* need a diff. comments div for each */
var post_id = $('.post').attr('data-post_id');
$.get({'/posts/'+post_id+'/comments', function(data){ comments_div.append(data); } });

Related

Rails 5 after submitting form / action stay on exactly the same spot on page

I have this webshop, and on one page you see
products;
with a submitting form for a booking;
your order with its bookings;
with a removing link for a booking;
and an updating form for a booking.
Both the order.bookings and the products make potentially long lists on a html page.
The whole booking works by only a booking_controller.
What the booking_controller does:
Takings in the (new) params of a single booking or the destroy action.
Saves the new order.
Redirects to the store.
Works fine, just using ruby and html.erb.
Only problem, and this really needs to change, is that obviously after each redirect the browser goes to the top of the page. The browser isn't focussed. Or better to say, the browser should remain, but doesn't.
I get that your doing all these things on the server-side, so a page reload, or better to say, data-refresh, is necessary. What I don't want is building this whole thing again on the client-side (JS).
Can't I simply say something like: after data refresh redirect to exact same spot on page. Ignoring all the difficulties an asynchronous request would give, or am I exaggerating and is a little JS easy?
With Rails, using ajax is very easy however if you're not familiar with ajax at all it can be a bit daunting at first. Luckily there are many tutorials on the subject. Basically, add the remote: true option to your form_for statement and rails will automatically understand you want it to make a 'POST' request in JS format. It's important to realize that the incoming HTTP request is in JS format because you'll then need to specify handling that event in the controller. Such as:
def create
#Do whatever saving and processing you need here
respond_to do |format|
format.html { redirect_to some_path_here }
format.js { } #By not adding anything in the brackets here, you're telling rails to fetch a js view file that follows standard rails convention and so it should be named 'create.js.erb'
end
Then in your controller's views folder create the view file create.js.erb. In that file you'll want to refresh whatever part of the page needs updating which usually involves hiding the old div that was there and appending a partial in its place. I usually leave an empty div with an ID on the page (in this case your new_whatever_page.html.erb that I then call in the js.erb file to append a partial to:
In your create.js.erb add:
$("#the-id-of-the-div-in-your-new-view-page").html("<%= escape_javascript(render 'order_table') %> #This basically says, find the div on the current page with a matching id and then append the partial named _order_table.html.erb to it.
Now just make a partial named
_order_table.html.erb
in the same views folder and put whatever content you want to insert or update.

Ajax updating pagination in rails

I have a page where a user can enter a message, and subsequently that message will appear below on the page. These messages are intended to be paginated.
I am trying to do this with Ajax. Currently my .js.erb file tells the page to re-render a partial in this way:
var submitted_message = $('<%= j(render 'shared/message_listing')%>');
$('#accordion').html(submitted_message);
The message_listing partial contains a pagination statement in it, like this:
<%paginate #messages, :params => { :anchor => "questions" })%>
However, when this line of code renders, the pagination buttons are produced but the url's associated with the links are incorrect. They should look something like
`test.com/client/messages?page=3&pr_rep_id=1047460791&project_id=864121040#questions
On normal page load, the pagination links look like this. Except the pagination urls generated by the ajax request look like this:
client/messages?authenticity_token=ro3YVz%2BnPR4JRC3GL7IVHRYA%2FcEYUjDVp27tDYukm7M%3D&message%5Bpr_rep_id%5D=1047460791&message%5Bproject_id%5D=864121040&message%5Btext%5D=a&page=2&utf8=✓#questions
This link somehow redirects me to an index page.
Does anyone know why the pagination generated by the ajax request looks different than it should? All of the pagination links are the same, and it looks like they don't have any page parameter. What can I do to make these links right? Is there a way I can hack up the Kaminari gem that I'm using?
Thanks!
The problem is that I'm using a POST request, in which parameters such as authenticity key are being passed by the kaminari gem. this is similar to this question:
Unwanted form parameters being appended to pagination links

RoR- How to use div onclick to render results in a separate area of the page?

I am learning Ruby on Rails, and I am very confused on how the controller-model-view relationship works for my application.
What I have now is a table full of comments (posts) users have made. What I want to do is let users click on a comment to see more information in a separate panel (ie, other database fields that weren't initially shown, for example the user_id of the person who posted the comment).
In my _post.html.erb, I have something like:
<div class="post" id="<%= post.post_id %>" onclick = ?? >
<p>post.text</p></div>
What should go in onclick? I need a way for the onclick to call a helper/controller method which can load more information, and then put that in another div on a page (I've tried variations of using the controller and helper to call javascript which inserts html into the site, but that seems messier than it should be). From what I understand, I should create some kind of partial _postdetails.html.erb file that handles the actual displaying of the html, but I have no idea how to specific where that partial would go in the page.
Any help would be appreciated, thanks!
You can achieve what you want either by using Rails helpers or by writing the AJAX calls yourself.
Personally I manually write all my AJAX calls using jQuery.
You can also use Prototype which ships with Rails.
That being said you can do.
In your JS file :
$("div.some-class").click(function()
{
$.ajax(
{
url:"url/to/controller/action",
type:<GET>/<POST>,
data://If you wish to sent any payload
});
});
In your controller :
def some_action
#some computation
render :update do |page|
page["id_of_div_to_be_refreshed"].replace_html :partial => "some_partial"
end
end

How can I re-populate a list in a <div> after adding an item to it using AJAX?

Specifically, I have a number of pages in my Rails app that use the same partial. In the action handler for each page I create an array object (e.g. #list_elements) based on a database query. Each page uses a different query so that each page has different list elements in it. At the top of each page I have a form_remote_tag containing an edit field, allowing the user to add a new element in a dynamic, AJAXy fashion (think something like Twitter 'What's happening' box).
My problem is that when the AJAX command fires I need to reload the list to include the newly added item, but the contents of the list were determined by a database query. I need to remember which query applies to the current page (i.e. controller action) so that I can run it again. I thought about storing something in the rails session structure but it seems like overkill - it's like storing the current page all the time.
Anybody done anything like this and have a nice Railsy way to achieve it?
Ben
Couldn't you just re-render the partial in your rjs template?
page[:div_element].replace_html :partial => 'partial'
If you perform the query and define the array in the controller action, then an ajax call will refresh that array.

How to create one form with many possible actions in Rails?

I want to create one form with 2 buttons in rails. Both forms operate on the same data in different ways, and I would prefer to keep the associated functionality in two different methods. Previously I've redirected to the appropriate method after doing a string comparision on params[:commit], but my gut says there's a better approach. Suggestions?
Two different submit buttons that send the form to two different actions:
<%= submit_tag('Insert', :onclick=>"document.myForm.action = 'insert';") %>
<%= submit_tag('Update', :onclick=>"document.myForm.action = 'update';") %>
Instead of "myForm" you need to put whatever is in the "name" property of your tag.
You can set that property in your default form:for tag like this:
<%= form_for(#something, :html => {:name => "myForm"}) do |f| %>
Without using JavaScript, your only solution is what you mention: checking which button was clicked by looking at the POST data in the controller. This is simply due to the nature of the HTML form element. It cannot have more than one value for its action attribute.
If you're not worried about what will happen when JavaScript isn't available, then you can write some script to change the action attribute when one of the submit buttons is clicked, prior to actually submitting the form. In the case of an ajax request, it could simply submit to the correct URL directly without altering attributes on the form.
I also used the params[:commit] method on a form already. Using the I18n helpers makes this a bit less fragile as you can use the same lookup in the view and controller, so you don't encounter the problem that the string changes a bit.
Besides that I can only think of using JavaScript to handle the clicks on the buttons and then send the form data to different Rails actions (Maybe you can change the HTML action attribute of the form with JavaScript before you submit the form).
If you're using prototype.js, you can use Form.serialize() to grab your data from your form and from there use the different buttons to post to different actions.

Resources