Paginate many has_many belongs_to relationships in Rails with will_paginate - ruby-on-rails

A user has_many potatoes. Potatoes belong_to a user. A potato has_many quirks. Quirks belong_to potatoes.
I want to display my potatoes and their associated quirks together in my Users show and Paginate using the will_paginate gem like below.
potato_names -> sweet potato russet potato mystery potato
quirk_name -> shiny rough purple
quirk_name -> big brown orange
quirk_name -> old medium blue
My users controller pre-pagination
UsersController
def show
#user = User.find(params[:id])
#potatoes = #user.potatoes
#quirks = Quirk.where(potato: #potatoes)
end
I can paginate potatoes by changing the UsersController -
#potatoes = #user.potatoes.paginate(page: params[:page])
and Users - show.html.erb
<%= #potatoes.potato_name %>
<%= will_paginate #potatoes %>
but how can I get quirks to paginate with the potatoes so that when I click next I get the potatoes and quirks associated with the next set? Initially I was getting potatoes to paginate and quirks to just show itself, which is why I didn't display quirks previously. I wasn't understanding the .pagination call well enough.
I can call :param_name to specify the parameter name for page number, and make sure that it's working appropriately.
will_paginate documentation
I can do
UsersController
def show
#user = User.find(params[:id])
#potatoes = #user.potatoes.paginate(page: params[:potatoes_page])
#quirks = Quirk.where(potato: #potatoes).paginate(page: params[:quirks_page])
end
show.html.erb
<%= render #potatoes %>
<%= render #quirks %>
<%= will_paginate #potatoes, :params_name => 'potatoes_page' %>
<%= will_paginate #quirks, :params_name => 'quirks_page' %>
_potato.html.erb
<%= potato.potato_name %>
_quirk.html.erb
<%= quirk.quirk_name %>
This should give me potatoes and quirks paging separately... But when I next page potatoes, potatoes is paging and quirks is disappearing. When I next page quirks page, potatoes stays the same and only quirks changes.
I believe that the above error is because I'm calling pagination in the potatoes query, then using the potatoes query to call pagination again.

The overall look should be:
UsersController
def show
#user = User.find(params[:id])
#potatoes = #user.potatoes.paginate(page: params[:page])
#quirks = Quirk.where(potato: #user.potatoes).paginate(page: params[:page])
end
show.html.erb
<%= render #potatoes %>
<%= render #quirks %>
<%= will_paginate #potatoes, :params_name => 'page' %>
_potato.html.erb
<%= potato.potato_name %>
_quirk.html.erb
<%= quirk.quirk_name %>
The error was in calling pagination on a pagination with #potatoes and #quirks in the UsersController. Additionally I changed :params_name back to the default page so both models would change at the same time. To change them separately, use potatoes_page and quirks_page as shown in the question. I also removed
<%= will_paginate #quirks %>
because I was getting two next bars. If you are changing #potatoes and #quirks separately, you would need to include it.

Related

how do i display an objects attributes from a different table in rails

Apologies if my terminology is off here.
I have a model for Users. I have a model for Products. Users have many products and Products belong to Users.
I am trying to have a Users index page that shows all Users and their associated Products with links to the individual User pages. My SHOW page is operating as I expect but I don't know how to show the User's Products on the index view.
SHOW (this works)
Controller
def show
#user = User.find(params[:id])
#product = #user.products
end
View
<%= #user.name %>
<% if #user.products.any? %>
Product
<%= render #product %>
<% end %>
Product Partial (referenced above)
Serial Number: <%= product.serial %>
INDEX (this does not work)
Controller
def index
#users = User.paginate(page: params[:page])
#product = #users.product #trying to show
end
View
I am at a loss here. Anything I've thought made sense doesn't work for me.
I would like to do something like
<%= user.product.serialnumber %>
or
<%= user.product.id %>
How do I show attributes of the User's Products in a view? Why does it work in a partial in my SHOW action/view but not in my INDEX action? Do I have to use a partial?
For your index action, #users is a collection of users whereas in your show #user is a single user object.
When you say, #users.product, you are calling product on collection object and not user object. So what you have to do is, iterate #users collection in your view and call product on the object
Something like
<% #users.each do |user| %>
<%user.products.each do |product|%>
<%= user.name%>
<%= product.serialnumber%>
<%= product.id%>
<%end%>
<% end %>

Having problems with putting database to use

So I have this books database and a burrows database. In burrows, there is a field for book_id and also a field for user_id, so that I can see who burrowed which book.
Now, I am trying to create a controller and view for it but it is not going well really. Right now the view is looking like this:
<% provide(:title, "Burrow") %>
<b align="center">Choose the name of the book you want t burrow'</b>
<%= form_for(#book) do |f| %>
<div class="forms">
<%= f.name %>
<%= f.check_box(:book_id) %>
<%= f.submit 'Submit!' %>
</div>
<% end %>
But this puts me to the problem where it creates an error because I want to put all books into #books in burrows controller. But I dont really see any other way? \
The final idea would be so that I have all the books displayed and after them a checkbox, so I can select which books I want to burrow. And after that I also want a dropdown menu where all users are listed, I can choose to burrow the book for another user, but the default value would be the logged in user but theres time till that. Right now I am struggline to understand, why my solution for listing books does not work?
Listing my controller here also:
class BurrowsController < ApplicationController
before_action :signed_in_user, only: [:index,:edit,:update, :destroy]
before_action :admin_user, only: :destroy
def index
#burrows = Burrow.all
end
def show
#burrow = Burrow.find(params[:id])
end
def new
#burrow = Burrow.new
end
def create
#burrow = Burrow.new(burrow_params)
if #burrow.save
flash[:success] = "Burrowing a book was successful!"
redirect_to #burrow
else
render 'new'
end
end
def listing
#book_list = Book.all
end
# Private section, makes the page unable to be seen for non logged in users
private
def burrow_params
params.require(:burrow).permit(:user_id, :book_id)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
# Redirecting not logged in user etc.
def signed_in_user
unless signed_in?
store_location
redirect_to '/sessions/new', notice: "Please sign in!"
end
end
end
Right now I am struggline to understand, why my solution for listing books does not work?
I'm not sure what listing you mean. The view you pasted apparently corresponds to the controller action Burrows#new?
So I'm going to tell you what's wrong with your view:
<%= form_for(#book) do |f| %>
This prints a form for a Book, not a Burrow. You could create a new book with this form, but that's certainly not what you're trying to do here.
You'll want to have all these variables in your controller:
def new
#users = User.all
#books = Book.all
#burrow = Burrow.new
end
so you can use collection_select with #users, have a #burrow object to use with form_for, and do a each loop on #books, for instance, like this:
<%= form_for(#burrow) do |f| %>
<% #books.each do |book| %>
<%= f.check_box :book_ids, multiple: true, book.id, nil %>
<% end %>
<%= f.collection_select :user_id, #users, :id, :name, {}, selected: current_user.id %>
<%= f.submit %>
<% end %>
Click the links for documentation on these commands: collection_select, check_box
This is not ideal code, but it's as close to your example as I can get.
I understand if you don't get this right away. Your code is a bit of a mess right now and there's too much wrong with it to be explained in one post and fixed by just one line. You might want to start over, and make a single controller action work before you try to make everything at once.
Sometimes it's better to sit back and really think about what you're trying to achieve, and first lay out how to achieve it inside your head; and only then start programming!
It seems to me that you're using the RailsTutorial by Michael Hartl, so all I can recommend to you right now is, read what you've read again more thoroughly and try to stick to his examples first until you feel confident, before really starting to make your very own application.

Rails: Rendering with Pagination Issues of a Comment Model

The current page that I have been working on is a page where a user can create a comment under a specific micropost. All the microposts are shown on the same page and those microposts are paginated. Under each specific micropost, there are comments and those comments should be paginated and the issue I am currently having is that the pagination only happens when the HTML code is this:
HTML
<div id='comments'>
<%=render #comments %>
<%= will_paginate #comments, :class =>"pagination" %>
</div>
But the thing is when it is like that only the comments for the first micropost will show up on every single micropost rather than the specific micropost comments. So I figured why not put the code like this:
HTML
<div id='comments'>
<%=render micropost.comments %>
<%= will_paginate #comments, :class =>"pagination" %>
</div>
This basically set all the specific comments in the right micropost BUT it didn't paginate but the pagination links showed, so I figured putting this would work but it didn't, got an error:
HTML
<div id='comments'>
<%=render micropost.comments %>
<%= will_paginate micropost.comments, :class =>"pagination" %>
</div>
I am very confused and unsure what to do and yes the micropost is suppose to have no #
I would appreicate any suggestions that would help! Thank you!
My User#Show
User Controller
class UsersController < ApplicationController
def show
#user = User.find_by_id(params[:id])
#school = School.find(params[:id])
#micropost = Micropost.new
#comment = Comment.new
#comment = #micropost.comments.build(params[:comment])
#comments = #micropost.comments.paginate(:page => params[:page], :per_page => 10)
#microposts = #user.microposts.paginate(:per_page => 10, :page => params[:page])
end
end
This will work, but the fact that you need to do an assignment inside your view tells you this is probably not the way to do it:
<div id='comments'>
<% comments = micropost.comments.paginate(:per_page => 10, :page => params[:page]) %>
<%= render comments %>
<%= will_paginate comments, :class =>"pagination" %>
</div>
Do realize that the micropost & comments both use the same page parameter. So that if you want to view the second page of comments of any of the given microposts you will also switch to the second page of microposts. I would reconsider showing all this information on the same page.

How do I display "wall posts" on a user's page?

I'm trying to show "wall posts" that all users have made on a specific user's page, but I'm having difficulty showing the correct posts.
Users controller:
def show
#user = User.find_by_cached_slug(params[:id])
#posts = Post.find_all_by_poster(params[#user.id])
if signed_in?
#post = Post.new
end
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
Post form:
<%= form_for #post do |f| %>
<div class="field">
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.hidden_field :user_id, :value => current_user.id %>
</div>
<div class="field">
<%= f.hidden_field :poster, :value => #user.id %.
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
When a user creates a post the current_user id is saved in the posts table as the :user_id and the user id of the user's page they're posting on is saved as :poster. This part is working, but I don't understand how to render #posts so that only the posts that have been made on that user's page appear.
The approach I'm trying is somehow showing/filtering? all posts where :poster matches the user id of the user's page; however, I don't know how to make this work or if there is a better way. Any help?
Note: I'm using the slugged gem. In the Users/show view, I use <%= render #posts %>. Eventually, I'd like for users to be able to comment on posts, if that affects any design decisions.
Thanks very much for your help! Please let me know if any more information is needed.
I think this line is the issue:
#posts = Post.find_all_by_poster(params[#user.id])
#user is the the record for the user who wall is now being viewed. (right?) You need all the posts that were posted to that users wall that is all the Post records where poster == #user.id. There is no need to look in the params hash for this. I believe that this line should instead be:
#posts = Post.find_all_by_poster(#user.id)
If this is incorrect, it means that I am not clear how your show action is meant to work. There are two different things that could be #user. By convention this should always refer to the record of the person at the other end of the connection. In your case, it looks like it instead refers to the person whose wall is being viewed. Is that correct?

Strange routing in rails render partials

I'm new to rails and thought I had finally figured out some of this routing stuff, but have been going in circles with this bit all day.
I was following a tutorial about building a twitter like service, and I've got the basics working from the tutorial, but with Mongo instead of mySql.
I've got 3 types of pages.
The home page which is showing all the posts ordered by date
The user page which is showing the posts from a specific user
The posts page which is showing posts from a users friends.
So for each page, I've done the following
1) created a method in the corresponding controller to get the correct posts
2) created a _posts.html.erb page with the display parameters, which are slightly different on each page
3) referenced the partial in the index.html.erb page for each view.
The controller entries look like this
def index
#posts = Post.all(:order => 'created_at DESC')
end
or
def posts
#posts = Post.all(:conditions => {'user_id' => params[:id]}, :order => 'created_at DESC')
end
and the partials are
<%= render :partial => #posts %>
In each view is a _posts.html.erb file, and each is slightly different
home/_posts.html.erb looks like this
<%= div_for post do %>
Posted <%= time_ago_in_words(post.created_at) %> ago
Posted By <%= post.user_id %>
<%= post.text %>
<% end %>
while posts/_post.html.erb looks like this
<%= div_for post do %>
Posted By <%= post.user_id %>
<%= post.text %>
<% if post.created_at > 52.hours.since %>
<%= distance_of_time_in_words_to_now(post.created_at) %>
<% else %>
<%= post.created_at.strftime("%c") %>
<% end %>
<% end %>
Now the strange part is that on all the pages index.html.erb, users/show.html.erb, posts/index.html.erb, the partial that is being displayed is the posts/_post.html.erb. The others are being completely ignored.
my understanding was that render :partial would take the #posts and render _posts.html.erb from the current view. But this isn't happening, as only the posts/_post.html.erb is being rendered from all views.
I've looked in the routes.rb file, but don't have anything in there that would cause this problem.
Can anybody tell me why I am not displaying the proper partials?
-----------Edited --------------------------------
The directory structure for views is as follows
views
- home
-_post.html.erb
-index.htlm.erb
- layouts
- posts
-_post.html.erb
-index.html.erb
-posts.html.erb
- sessions
- users
-_post.html.erb
-new.html.erb
-show.html.erb
I hope that helps.
"post", :collection => #posts%>
maybe rails automatically defines path to the partial when you pass only collection
You're passing the collection as the argument that rails is expecting to be the name of the partial. Your call to render should look like this
<%= render partial: "post", collection: #posts %>
This will render app/views/posts/_post.html.erb, passing the local variable post to the partial.
Additionally, (is sometimes handy) there's an iteration object that is made available to this view, partial_name_iteration, that has information about the total size of the #posts collection, and the index of the current object.

Resources