Lemme explain what I mean, the point is that I am using acts_as_votable gem in my rails app and it works fyn, problem is that I am using ajax and I am using it to like individual posts from my index page . I will explain with the code
This is my #confessions controller instance variable that has all the votes
#confessions = Confession.where(amitian_id: ids).order('created_at DESC')
Now this is my view that shows all the posts
-#confessions.each do |c|
# code
=link_to pluralize(c.get_upvotes.size,"Like"),like_confession_path(c) , method: :get,remote: true , class: 'like'
=link_to pluralize(c.get_downvotes.size,"Dislike"),dislike_confession_path(c) , method: :get,remote: true ,class: 'dislike'
end
Well, up until now I can use 'c' variable to refer to a single post.. but in my ajax script I have something like this
$('.like').html('<%= pluralize(#confessions.get_upvotes.size,"Like") %>');
$('.dislike').html('<%= pluralize(#confessions.get_downvotes.size,"Dislike") %>');
Now obviously, this will like all the post variable #confessions have.. how can i write a script to make it like the post user clicks on
I suppose I have to use this or self keyword but m not sure how.. help plz
Move the confessions block to a separate partial. Then wrap that partial in a div. Then in your ajax script you can just reload the partial.
View:
<div id=confessions>
<%= render 'confessions' %>
</div>
Ajax
$('#confessions').html("<%= escape_javascript(render 'confessions') %>")
Also, are you sure you want to be making GET requests to like/dislike? I think you should be making a POST request here.
Related
I switched my advanced order form to POST from GET as the URI request became too large for browsers to handle. Everything works fine, with the exception of will pagaination. It keeps adding the page to the url itself http://localhost:3000/orders/advanced_search like http://localhost:3000/orders/advanced_search?page=2 which fails as this is a post call, and not a get call.
Any way that it can just update the params[:page] but not do anything to the link?
I used to just call <%= will_paginate #orders["order_items"] %> which worked great when it was a GET call where
#orders["order_items"] = #orders["order_items"].paginate(:page => params[:page],
:per_page => limit, :total_entries=>#orders["total"])
What I want is simple, add it to params, but do not add it to the link.
The other answer posted is wrong. will_paginate was NOT built to work with post requests.
Your choices to 'make' will_paginate work with post request include:
writing some javascript to:
preventDefault on click of the will_paginate-generated link
$(".pagination li a").click(function(e){
e.preventDefault(); ....
find the target page via the clicked link.
(below code is assuming all will_paginate links have a query string...which they do. But note that this particular line of code won't work if you are passing in more params in the controller via the params option for will_paginate..which you shouldn't be in the first place because we are trying to achieve a post request.)
var tp_id = $(this).attr("href").split('?page=')[1]
generate a hidden input with the correct name attribute depending on the clicked will_paginate link.
$('form').append("< input type='hidden' name='page' value='" + tp_id +"' >")
finally post to the controller action of the search form.
$('form').submit()
.done. I hope this puts you on the right path.
You can add a param to will_paginate
https://github.com/mislav/will_paginate/wiki/API-documentation
<%= will_paginate #orders['order_items'], :params => { :method => :post } %>
If it doesn't work, set te complete controller and action to params.
Thanks for your time!
I get some reports data on my hand and I want to present these data on the web. The view of the HTML will be divided into two parts, the left part and the right part. There's a tree view in the left part consisting of the report names. In the right part presents the contents of the report.
What I want to achieve is when I click the report name on the left part, it will call an Action in the Controller, and passed the report name as parameter. The Action will fetch the data from the database and represent the data in the right part. And now I am stuck on how to realize this kind of view.
I've Googled a lot on the Internet and found Frameset, Partials or Ajax may capable of this. Because I've never developed web applications before and also new to Rails. So can anyone give me some advise or suggestion?
Things I've already known :
I've used Frameset to accomplish a view like this. But I found it needs a lot of .html files and all these .html files are static. And many people don't suggest it at all.
Then I've Googled Partials. But it seems Partials don't call the Action. It directly loads the _partials.html.erb to the main view. And besides, how can I control the layout? Using CSS?
I've never used Ajax.
If you want a fluid, seamless transition between one report and another, you should use both AJAX and Partials.
The way that it works is something like:
Make a left column in the html that has some links
Make the right column inside a partial
Assign the links to jQuery listeners to call the AJAX.
I'll put a bit of code here to show how it works:
Controller:
def index
reports = Report.all
if params[:report_id]
reports = Report.find(params[:report_id]
end
respond_to do |format|
format.html
format.js { render :template => "update_reports" }
end
end
update_reports.js.erb (in the same folder as the report views):
$('#report_viewer').html('<%= escape_javascript render :partial => "report_detail" %>');
In your view:
<div style=float:left>
<ul>
<li><%= link_to "Some report", "#", :class => "ajax" %></li>
</ul>
</div>
<div style=float:right id="report_viewer">
<%= render :partial => "report_detail" %>
</div>
<script type='text/javascript'>
$(document).ready(function() {
$(".ajax").click(function(e) {
$(this).ajax("your route to the action");
}
});
</script>
I think it's basically this, now let me explain a few things:
I don't remember if you have to do this, but in my case I created a new custom route to force the call to the action to be a json call instead of a html one. You can do this by adding :format => "js" to your route
You must name all your partials like "_yourname.html.erb". Rails won't recognize partials without the leading underscore.
In the controller, everything that comes after "format.js" is optional, you don't need to specify the template name, and if you don't Rails will look for the file index.js.erb.
The update_reports.js.erb file is basically a callback javascript that executes to update the current page. It finds the div where the partial is, and updates it rendering a new partial with the new report.
In the view, the link to change the report don't need to be a link at all if you're using the jQuery.click listener, but if it is a link, it must have the href as "#", or else the browser will just try to redirect to that location.
There are several ways to hook your link to the ajax function, I just chose the one I like it better, but you also could have a named function and call it in the html tag "onClick='yourFunction()'".
You need jQuery to call ajax like this. If you're sing Rails 3.0 or lower, you should replace the default Prototype with jQuery, because it's much better (IMHO), but I think prototype also have some ajax features.
It may seem complicated, but once you get the idea of it it'll become simple as writing any other action.
In the js callback file you could also add an animation to smooth the transition, like a fading. Look for the jQuery fade function for more info on this.
This is quite an open question so don't take this answer verbatim, but merely as a guide.
app/views/layouts/reports.html.erb
<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/">
<head>
# omitted
</head>
<body>
<div id="body-container">
<div id="left-column">
<ul id="reports-list">
<% for report in #reports %>
<li><%= link_to report.name, report %></li>
<% end %>
</ul>
</div>
<div id="right-column">
<%= yield %>
</div>
</div>
</body>
</html>
app/controllers/reports_controller.rb
class ReportsController < ApplicationController
before_filter { #reports = Report.all }
def index
end
def show
#report = Report.find(params[:id])
end
def edit
#report = Report.find(params[:id])
end
def new
#report = Report.new
end
def update
# omitted
end
def create
# omitted
end
def destroy
#report = Report.find(params[:id])
end
end
routes.rb
YourApp::Application.routes.draw do
resources :reports
root to: "reports#index"
end
This would achieve the effect your after using just rails, of course adding ajax could add a better user experience.
UPDATE 3:
For anyone who reads this, this is why it wasn't working as expected in update 2 below: Passing a local variable to a partial that is rendered after the view has already loaded
If anyone knows how to solve that issue, let me know please.
UPDATE 2:
I updated the javascript with the quotation marks and it partially works...in the sense that the javascript is now functional and it will cause a string of text to appear on the page when I click the link as long as I have the partial only contain a string of text. However, when the partial includes the form fields code, something goes wrong.
If I just paste the following render code directly into the form in the new.html.erb view, it produces a new form section properly.
<%= render "add_round", f: f %>
However, when I try to include similar code in comps_helper.rb and then reference it from the link_to, it does not work:
In comps_helper.rb:
def addRound(f)
render "add_round", f: f
end
In new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
And I changed addRoundLink.js.erb to:
$("#some_id").html("<%=j addRound(f) %>"); #Is this the correct change to have made here?
Clicking the link_to link does nothing in that case.
Any thoughts?
UPDATED CODE:
Thanks for the reply. I've made the following changes and it still does not appear to be working. The link appears at the bottom of the form but when clicked does not change anything. What am I missing?
routes.rb:
resources :comps
match '/new_competition', :to => "comps#new"
get "/addRoundLink" => "comps#addRoundLink", :as => :addRoundLink
Note: I included the other 2 lines related to "comps" just in case those would cause an issue.
comps_controller.rb:
def addRoundLink
respond_to do |format|
format.js
end
end
comps_helper.rb:
def addRound
render "add_round"
end
addRoundLink.js.erb:
$("#some_id").html(<%=j addRound %>);
comps/new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
Thanks.
ORIGINAL QUESTION
First off, I'm new to rails. I've read and tried many solutions to similar questions but nothing has worked so far.
I created a form with rails form_for and fields_for. The form creates a new competition (comp). The competition has many rounds. The top half of the form (the form_for section) accepts the details about the competition as inputs and the bottom half of the form accepts details about each round (the fields_for section). The form works perfectly in this basic format.
I took all the code that is in the fields_for section and put it into a partial. My plan was to then create a "add new round" link to the bottom of the form that would simply display the partial above the link each time the link is pressed. This would add a new section to the form for a new round and allow the user to input as many rounds as they'd like. This is the part that I am struggling to make work.
I added this code to my comps_helper:
def addNewRound
render "add_round"
end
This renders the file /views/comps/_add_round.html.erb.
My question is: how do I get this to render in the form when a link is clicked. As far as I can get with the research I have done is:
<%= link_to "Add new round", { }, :remote => true %>
I don't exactly know what is supposed to go in the {} that will execute the addNewRound method. And I don't know what, if anything, I need to add to my comps_controller file.
Thanks so much for the help.
You have to create an action in your controller
app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
and define a route to this action.
routes.rb
get "/hello" => "some#hello", :as => :hello
then create a link to this action like that:
<%= link_to "render it!", hello_path, remote: true %>
<div id="some_id"></div>
When you click this link it will find its way to your action and respond with js(javascript) because we told action to respond with only js.
At the end render the partial to anywhere you want in your view(*in this example to the some_id div*)
app/views/some/hello.js.erb
$("#some_id").html("<%=j addNewRound %>");
WARNING: Creating dynamic forms is a pain. You will face a lot of problems (like setting different ids for new form elements etc...). I highly recommend you to use ryan bates nested_form gem
This is blowing my mind, and there is so much going on that I just need to ask here for help.
Right now, I have a listing of resources. Inside each resource, it allows someone to 'add it as a favorite' by clicking a link. I have it working with normal redirection, but as for integrating ajax so they can favorite without the page refreshing, I am completely lost...
Right now I have it as a "put" action it seems for CRUD 'update'
FavoritesController (update is the only action in this controller)
def update
#favorite = Favorite.find_or_initialize_by_resource_id_and_user_id(params[:id], current_user.id)
if #favorite.persisted?
#favorite.destroy
else
if #favorite.valid?
#favorite.save
end
end
redirect_to root_url
end
My view:
<%= link_to "", favorites_path(:id => resource.id), :class => "star#{star_post?(resource)}", :method => "put" %>
My routes:
resource :favorites, :only => [:update]
My JS:
$('.res-list .star').click(function(){
$.put('/favorites/?id=' + $(this).attr('data-id'));
return false;
});
There's a couple of ways to do this. You can use link_to_function through which you can pass a javascript method (you can even pass a custom one if you've defined it in the view or in application.js). In this method, you can set up your AJAX call to hit your update action.
View (using jQuery's put macro):
<%= link_to_function "AJAX Link", "$.put('/favorites/#{resource.id}');" %>
Another way to do this is to give your link an addition HTML selector. Again, you would need to write a bit of js to hit your update action. I tend to like this way because I like to use buttons and what not instead of <a href="#"> tags. (Though honestly I ended up just creating a button_to_function method that calls content_tag(:button) instead of content_tag(:a))
I would recommend starting off with this Railscast on basic JQuery and Ajax processing. It's a bit dated, but is pretty solid still and will give you the basics to get you started.
http://railscasts.com/episodes/136-jquery
It will give you an idea of how to attach the ajax call to the element on your page, handle request processing and craft a basic javascript view partial that will update the form for the user.
Good luck!
If you google "will_paginate" and "ajax", the top result is this blog post: But the original author of will_paginate says to not use this method (bad for SEO/spiders) ...
But I cant get the original authors method to work (his javascript kills all my links). An other gentleman suggests a similar method to mislav's (the original will_paginate author) concept. But I cant get that to work either.
so .... what is the best way to paginate using AJAX, and stay SEO friendly? (for RAILS >2.1)
Tomh's answer is correct. Just for shiggles, I prototyped a quick implementation. Here's a screencast that shows it using Ajax when Javascript is enabled (your users) and still having pretty URLs when Javascript is disabled (Google). And here are a few code snippets to get you rolling on it.
config/routes.rb:
map.connect 'items/:page', :controller => "items", :action => "index", :page => 1
app/controllers/items_controller.rb:
class ItemsController < ApplicationController
def index
#items = Item.paginate(:all, :page => params[:page])
respond_to do |format|
format.html
format.js do
render :update do |page|
page.replace_html :items, :partial => "items"
page << "ajaxifyPagination();"
end
end
end
end
end
app/views/items/index.html.erb:
<h1>Listing items</h1>
<div id="items">
<%= render :partial => "items" %>
</div>
app/views/items/_items.html.erb:
<%= will_paginate #items %>
<table>
<% for item in #items %>
<tr>
<td><%= item.id %></td>
</tr>
<% end %>
</table>
layout:
<%= javascript_include_tag :defaults %>
public/javascripts/application.js:
$(document).ready(function() {
ajaxifyPagination();
});
function ajaxifyPagination() {
$(".pagination a").click(function() {
$.ajax({
type: "GET",
url: $(this).attr("href"),
dataType: "script"
});
return false;
});
}
My example uses jQuery (with jRails), but it's straightforward to do with Prototype as well.
Seo friendly and unobtrusive javascript goes hand in hand. What you can do is the following.
Code the entire site as if only html is enabled (incl your pagination thing)
Use respond_to and serve only the list of items if the request comes in from js
Using onDomReady from whatever library you pick you attempt to catch all pagination links and add an onclick event which triggers an ajax call to that new view and returns the result. You put that result into the container containing the data you are paginating. The onclick then returns false.
To give your users a better user experience you can add some features like active links etc to the same javascript method.
Using this approach the pagination will work for JS and non-js as the non-js users (including Googlebot) will traverse your pagination as normal. Only in the event that the user has javascript enabled, the container with data will be updated with new results.
Unfortunately, I don't think you can use Ajax in the way you want and still stay SEO friendly as far as the paginated content. The problem is that the robots of Google and friends, as far as I know, won't go through your content using XHR requests so they simply won't see that content.
That said, if the paginated items each have their own static, SEO-friendly pages (or are otherwise statically available on your site), the content will still find its way into their engines. This is the way you'll probably want to go.
There is a railscasts on this topic which helped me out http://railscasts.com/episodes/174-pagination-with-ajax
I'm running rails 3.2, so I added the pagination.js there mentioned to app/assets/javascripts folder
pagination.js
$(function() {
$(".pagination a").live("click", function() {
$(".pagination").html("Loading...");
$.getScript(this.href);
return false;
});
});
And then created
home.js.erb
$('#div_tags_list').html('<%= escape_javascript(render partial: '/customersb2b/user_customer_numbers_list').html_safe %>')
$('#receipts_list').html('<%= escape_javascript(render partial: '/customersb2b/feed').html_safe %>')
Since I have two distinct listings on my homepage.
This is all I had to do to put will_paginate working with Ajax.
As for the SEO concerns, well, I don't know much about it, but the URL http://localhost:3000/customers?_=1366372168315&feed_page=1&tags_page=2 still works
There is a great way to do this easily if not worried about spiders. Took me 5 minutes. Check out:
https://github.com/ronalchn/ajax_pagination/wiki/Adding-AJAX-to-will_paginate
If you get an error about a missing 'history' file, install:
https://github.com/wweidendorf/jquery-historyjs
but also be aware of:
rails ajax_pagination couldn't find file 'history'