Rails: Will_paginate does not work properly after AJAX call - ruby-on-rails

Sorry about the repetition, I could not find the answers to my questions after a lot of searches. The will_paginate does not work after the Ajax call.
After delete action, It does not display the pages numbers at all (it simply returns all results).
After search action, the page number does not update, it shows more pages than what should actually be there.
Here is the controller code.
class CitiesController < ApplicationController
def index
#cities = City.get_cities(params[:city_name],params[:city_population]).paginate(:page => params[:page])
respond_to do |format|
format.html
format.js
end
end
def create
#city = City.new(params[:city])
if #city.save
flash[:success] = "City information saved successfully"
redirect_to cities_path
else
render 'index'
end
end
def new
#city = City.new
end
def destroy
#city = City.find(params[:id]).destroy
#city.destroy
#cities = City.all
respond_to do |format|
format.html {redirect_to cities_path}
format.js
end
end
end
Here is the index view:
<div class="row">
<h1>Search Cities or <%= link_to "Create New City", new_city_path %></h1>
<h3>99 random city information are generated in the database </h2>
<h3>Simply type any letter or city population between 0 and 10 to filter out</h3>
<%= form_tag "/cities/index", method: :get, remote: true do %>
<%= label_tag(:q, "City Name:") %>
<%= text_field_tag 'city_name' %>
<%= label_tag(:q, "City Population greater than, in units of 1 million:") %>
<%= text_field_tag 'city_population' %>
<label></label>
<%= button_tag("Search", :class => "btn") %>
<% end %>
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>"><%= value %></div>
<% end %>
<div id='table' class="table table-striped">
<%= render 'table' %>
</div>
<%=will_paginate #cities %>
</div>
Here is the partial view of the table:
<div class="row">
<h1>Enter City descriptions or <%= link_to "Search Cities", cities_path %></h1>
<%= form_for #city, html: {multipart: true} do |f| %>
<%= f.label :city_name %>
<%= f.text_field :city_name %>
<%= f.label :city_description %>
<%= f.text_field :city_description %>
<%= f.label :city_population_in_units_of_millions %>
<%= f.text_field :city_population %>
<label></label>
<%= f.file_field :image%>
<label></label>
<%= f.submit "Create new City", :class => "btn"%>
<% end %>
</div>
Finally two js.erb codes associated with index and delete actions:
index.js.erb:
$('#table').html('<%= escape_javascript(render('table')) %>');
destroy.js.erb:
$('#table').html('<%= escape_javascript(render('table')) %>');

Found the solution by myself.
add <%= will_paginate #cities %> into partial file
and change #cities = City.all to
#cities = City.all.paginate(page: params[:page])
because will_paginate does not expect an array of objects.

write in your controller
def index
#cities = City.get_cities(params[:city_name],params[:city_population]).paginate(:page => params[:page])
respond_to do |format|
format.html
format.js
end
end
in your view folder create index.js.erb and write
$('id or class').html('<%=escape_javascript render :partial => which part you update %>')

Related

more rails partials on the same page

I have a rails app. I'm displaying more partials (user, task, conversation, message) from different classes on the users/:id/show page. I set all the instance variables (for other classes as well) in the users.controller's def show action.
It seems to be a bit heavy, so is there a better approach than this? (I'm using #task and #message for the AJAX calls.)
def show
#user = User.find(params[:id])
if Task.between(current_user.id, #user.id).present?
#tasks = Task.uncompleted.between(current_user.id, #user.id).order("created_at DESC").includes(:assigner).paginate(page: params[:page], per_page: 12)
#task = Task.new
if Conversation.between(current_user.id, #user.id).present?
#conversation = Conversation.between(current_user.id, #user.id).first
#messages = #conversation.messages.includes(:user)
#message = Message.new
respond_to do |format|
format.html
format.js { render :template => "tasks/update.js.erb", :template => "tasks/destroy.js.erb", layout: false }
end
end
else
redirect_to user_profile_path(#user)
end
end
UPDATED:
users/show:
<%if #conversation%>
<%= render 'conversations/show' %>
<% end %>
<tbody class="newtaskinsert2">
<%= render partial: "tasks/task_between", collection: #tasks, as: :task %>
</tbody>
conversations/_show:
<div class="chatboxcontent">
<% if #messages.any? %>
<%= render #messages %>
<% end %>
</div>
<div class="chatboxinput">
<%= form_for([#conversation, #message], :remote => true, :html => {id: "conversation_form_#{#conversation.id}"}) do |f| %>
<%= f.text_area :body, class: "chatboxtextarea", "data-cid" => #conversation.id %>
<% end %>
<%= form_for([#conversation, #message], html: {class: "refile_form"}, remote: true) do |form| %>
<span class="btn btn-success btn-sm btn-file">Choose file
<%= form.attachment_field :message_attachment, direct: true, presigned: true, class: "choosefile" %></span>
<%= form.submit "Send File", class: "btn btn-primary btn-sm btn-submit-refile", style:"display:none"%>
<% end %>
<span id="progresspercent"></span>
</div>
You can keep only #user instance variable in the controller, and in partials use: #user.tasks instead of #tasks, #user.tasks.new instead of #task etc. Note also, that you can pass parameters to partials (3.4.4 Passing Local Variables)
For sample:
<%= render partial: "your_partial", locals: {tasks: #user.tasks} %>
Update:
With your way (call methods from class instead of objects) you can do something like it:
def show
#user = User.find(params[:id])
if Task.between(current_user.id, #user.id).present?
# #user.tasks.where(another_user_field_name: current_user).present? - looks more like Rails way
#tasks = Task.uncompleted.between(current_user.id, #user.id).order("created_at DESC").includes(:assigner).paginate(page: params[:page], per_page: 12)
#conversation = Conversation.between(current_user.id, #user.id).first
if #conversation
respond_to do |format|
format.html
format.js { render :template => "tasks/update.js.erb", :template => "tasks/destroy.js.erb", layout: false }
end
end
# Do not forget that if #conversation is not exists this code render views by default way
else
redirect_to user_profile_path(#user)
end
end
<%= render 'conversations/show' %>
<tbody class="newtaskinsert2">
<%= render partial: "tasks/task_between"%>
</tbody>
<%if #conversation%>
<div class="chatboxcontent">
<%= render '_your_messages_partial', locals: {messages: #conversation.messages.includes(:user)}%>
</div>
<div class="chatboxinput">
<%= form_for([#conversation, #conversation.messages.new], :remote => true, :html => {id: "conversation_form_#{#conversation.id}"}) do |f| %>
<%= f.text_area :body, class: "chatboxtextarea", "data-cid" => #conversation.id %>
<% end %>
<%= form_for([#conversation, #conversation.messages.new], html: {class: "refile_form"}, remote: true) do |form| %>
<span class="btn btn-success btn-sm btn-file">Choose file
<%= form.attachment_field :message_attachment, direct: true, presigned: true, class: "choosefile" %></span>
<%= form.submit "Send File", class: "btn btn-primary btn-sm btn-submit-refile", style:"display:none"%>
<% end %>
<span id="progresspercent"></span>
</div>
<% end %>
You can make this code more shorter in case of using relations (#user.conversations instead of Conversation.between... etc)
I would suggest to use caching techniques for your views:
http://edgeguides.rubyonrails.org/caching_with_rails.html#fragment-caching
http://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching
In the extreme scenario where performance is still an issue for you, I would recommend to start denormalising the partials until you re happy with the performance.

How do I re-populate form fields when validation fails?

This is the erb template:
<div id='recipe-form'>
<% if #recipe.errors %>
<div id='errors'>
<% #recipe.errors.messages.each do |field, messages| %>
<div class='error'>
<div class=field'><%= field %></div>
<div class='messages'>
<ul>
<% messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
</div>
<% end %>
<%= form_for #recipe, :html => {:multipart => true}, :url => '/recipes' do |f| %>
<%= f.label :title, 'title' %>
<%= f.text_field :title %>
<div id="photo-upload">
<%= file_field :photo0, :image, :id => 0 %>
</div>
<div id='existing-photos'>
<% recipe.photos.each do |photo| %>
<div id='<%= photo.id %>'>
<img src='<%= photo.image.url(:thumb) %>' />
<ul>
<li>
<%= link_to 'delete',
recipe_photo_url(
:recipe_id => #recipe.slug,
:id => photo.id
),
:method => :delete,
:remote => true
%>
</li>
</ul>
</div>
<% end %>
</div>
<%= f.label :body, 'body' %>
<%= f.cktext_area :body, :ckeditor => {:width => "500"} %>
<%= f.label :tags, 'tags (comma separated)' %>
<%= text_field_tag :tags %>
<%= submit_tag 'submit' %>
<% end %>
</div>
This is the create action:
def create
#recipe = Recipe.new(params[:recipe])
photo_keys = params.keys.select{|k|k.match(/^photo/)}
#photos = []
photo_keys.each do |photo_key|
#photos << Photo.new(params[photo_key])
end
#recipe.tags = Tag.parse(params[:tags])
#recipe.author = current_user
if #recipe.save &&
#photos.all?{|photo|photo.save}
#photos.each do |photo|
photo.recipe_id = #recipe.id
photo.save
end
flash[:notice] = 'Recipe was successfully created.'
redirect_to recipe_url(#recipe.slug)
else
flash[:error] = 'Could not create recipe. '
flash[:error] += 'Please correct any mistakes below.'
render :action => :new
end
end
And this is the new action:
def new
#recipe = Recipe.new
end
I read that if I use form_for as I am using above, the fields will be re-populated automatically.
When I inspect #recipe.errors from within the erb template, I can see that the errors generated by create are also available when the new action is rendered, but the fields do not re-populate.
I'm actually not sure about what render action: does but what I do and works is: Instead of rendering the action just render the template using render :new.
You need to set the same instance variables (those with #), which you already in your create action.

Rails - AJAX/JQuery not working

For my application, I have projects where users can make comment (class Newcomments) postings. Right now it posts great but on page refresh. I am trying to use AJAX/JQUERY so that it will post with no page refresh. I am following this railscasts tutorial.
So right now, the posts are made to my database and the page does not refresh. But when I refresh, the posts shows up. The page that I render my comments for a specific project is on the projects/_comments.html.erb.
Question: How would I adjust it so that it the new comment made renders?
newcomments_controller.rb
def create
#newcomment = #commentable.newcomments.new(params[:newcomment])
if #newcomment.save
respond_to do |format|
format.html { redirect_to comments_project_path(#commentable) }
format.js
end
else
render :new
end
end
view/newcomments/_form.html.erb
<span class="comment">
<%= form_for [#commentable, #newcomment], remote: true do |f| %>
<%= f.text_area :content, rows: 3, :class => "span8" %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.submit "Add Comment", :class => "btn btn-header" %>
<% end %>
</span>
view/newcomments/create.js.erb
$('#newcomment').append('<%= j render(#newcomments) %>');
projects_controller.rb
def comments
#commentable = #project
#newcomments = #commentable.newcomments.newest.page(params[:comments_page]).per_page(10)
#newcomment = Newcomment.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #project.comments }
end
end
projects/comments.html.erb
<%= render 'comments' %>
projects/_comments.html.erb
<%= render #newcomments %>
view/newcomments/_newcomment.html.erb
<div class="comments">
<%= link_to newcomment.user.name %></strong>
Posted <%= time_ago_in_words(newcomment.created_at) %> ago
<%= newcomment.content %>
</div>
<span class="comment">
<%= form_for [#commentable, #newcomment] do |f| %>
<div class="field">
<%= f.text_area :content, rows: 3, :class => "span8" %>
</div>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="actions">
<%= f.submit "Add Comment", :class => "btn btn-header" %>
</div>
<% end %>
<% unless newcomment.newcomments.empty? %>
<%= render #newcomments %>
<% end %>
</span>
Try binding AJAX actions as described here:
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
Also, consider returning a render comments partial html instead of json comment object, to do so you need to tell in form after :remote directive that :'data-type'=>'html', so that returned html will hit function binded on AJAX success, and then swap html of container div with, for example, jQuery

retrieving multiple model objects from rails partial form

I have the below form working as a partial, i'm trying to do a partial call for a Contractors models and i want to also pass the current page's model id which is a quote id.
Its failing on this line <%= hidden_field_tag :quote_id, #quote.id %> 'called id for nil'
I've tried creating a manual route and putting the search on a seperate method, but then i get a template error so i'm just leaving it in the index method for now.
Form in show.html.erb:
<%= form_tag quotes_path, :method => 'get', :id => "contractors_search" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<br><br><br>
<div id="contractors"><%= render 'contractors' %></div>
<% end %>
_contractors.html.erb
<table>
<% #contractors.each do | contractor | %>
<tr>
<td><%= contractor.firstname %></td>
<td>
<%= form_tag (quote_add_contractor_path) do %>
<%= hidden_field_tag :quote_id, #quote.id %>
<%= hidden_field_tag :contractor_id, contractor.id %>
<%= submit_tag "Add" %>
<% end %>
</td>
</tr>
<% end %>
</table>
Index.js.erb
$("#contractors").html("<%= escape_javascript(render :partial => "contractors") %>");
Controller:
def index
#quotes = Quote.all
#contractors = Contractor.search(params[:search])
end
def add_contractor
#quote = Quote.find(params[:quote_id])
#contractor = Contractor.find(params[:contractor_id])
#quote.contractors << #contractor
if #quote.save
redirect_to #quote, notice: "contractor was added"
else
render :show, notice: "Sorry, something went aweful"
end
end
In index.js.erb you render the partial contractors but you do not set the #quote instance variable in your index action of the controller. That is why you are getting this failure. Try to add #quote = # Some logic here to your index action.

Rails 3.1 - Extra result of each loop?

This is really simple, but i'm going slightly mad and probably missing something that's staring me in the face. Can anyone help?
Basically, I have a simple each loop that's returning an extra rogue line. Even when there's nothing in the db, I get one line returned!
My show view including the loop is:
<p id="notice"><%= notice %></p>
<p>
<b>Header:</b>
<%= #mailer.header %>
</p>
<p>
<b>Subtext:</b>
<%= #mailer.subtext %>
</p>
<div id="" class="" padding-left: 30px;>
<h3>Mailer Products </h3>
<ol id="mailer-Product-list">
<% #mailer.mailer_products.sort_by { |mailer_products| mailer_products.position }.each do |mailer_product| %>
<%= content_tag_for :li, mailer_product do %>
<%= mailer_product.product.cat_no %>
<% end %>
<% end %>
</ol>
<%#= link_to 'Done', #product, :class => "standard-button" %>
</div>
<%= form_for([#mailer,#mailer.mailer_products.build]) do |f| %>
<div class="field">
<%= f.label :product_id %><br />
<%= f.text_field :product_id %>
</div>
<div class="field">
<%= f.hidden_field :mailer_id, :value => #mailer.id %>
</div>
<div class="actions">
<%= f.submit "Add Product" %>
</div>
<% end %>
<%= link_to 'Edit', edit_mailer_path(#mailer) %> |
<%= link_to 'Back', mailers_path %>
The controller code is:
class MailersController < ApplicationController
def show
#mailer = Mailer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #mailer }
end
end
class MailerProductsController < ApplicationController
def index
#mailer_products = MailerProduct.find(:all)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #mailer_products }
end
end
end
end
Your call to form_for looks like this
form_for([#mailer,#mailer.mailer_products.build]) do |f|
You get an extra blank item because that's what calling .build on mailer_products does: it appends a new instance to the array
When the form is after the loop this doesn't matter, but when things are the other way around the loop will be on the modified array
My usual mistake is adding a <%= instead of a <% on the loop...
<%= #foo.each do |itme| %>
# do stuff
<% end %>
which should be
<% #foo.each do |itme| %>
# do stuff
<% end %>
Double check your tags...

Resources