List all posts on Show view page - Rails - ruby-on-rails

I'd like to make a list of posts on the app/views/posts/show.html.erb page and sort each by id.
Similar to how all of the posts are listed on my app/views/posts/index.html.erb page using the code block below:
<% #posts.each do |post| %>
<div class="col-md-4">
<%= image_tag post.img %>
<h1><%= post.title %></h1>
<p><%= post.content %></p>
<br>
<%= link_to 'Read More', post_path(post) %>
</div>
<% end %>
When I try to use the same each do method on the show page I get an error. But this is what I currently have (it only displays an img/link to the current post):
<h1>Recent Posts</h1>
<ul>
<li>
<%= image_tag #post.img %>
<h2>
<%= link_to #post.title %>
</h2>
</li>
</ul>

Index is for displaying all the items of x.
def index
#posts = Post.all
end
So what you are doing is taking all your posts, and putting them in an array called #posts. You can iterate or enumerate over those with .each do |x|. That means go through each object in the array and show the post image, title and content.
You didn't display your show, but typically a show looks like:
def show
#post = Post.find(params[:id])
end
So you are finding the post with :id and storing that data in #post. This is only 1 object, it's not an array. That's why your .each do |x| isn't working.
There is nothing stopping you from making
def show
#posts = Post.all
end
But then you can't take advantage of rails shortcuts and are repeating yourself, which isn't good in programming. If you want two very distinct windows that use the same information, it's better to figure that out in html/css with a bit of javascript.

The show action of your PostsController is probably only setting up #post, and not #posts. You can't use .each with #post because it's an instance of Post, and not an array, or something that responds to .each. Look at how #posts is set up in the index action, and copy that to your show action.

Related

How to exclude current item from related item search

I have a post view where I want to display related posts but what I have now includes the current post as well.
How would I go about removing the current item from the search?
I don't know how to use where.not() or != in this situation or if they're even the best thing to use.
This is what I have in my post show view:
<% #related[#post.blog_category_id]&.each do |rel| %>
<a href="/posts/<%= rel.friendly_id %>" class="img-cont">
<%= image_tag("Index/#{rel.thumbnail_link}", :alt => "#{rel.title}", class: "soundtrack-img top-drop") %>
<div class="img-mdl wellington"><h3 class="img-txt basic"><%= rel.title %></h3></div>
</a>
<% end %>
And in my posts_controller show method:
#related = Post.friendly.all.group_by(&:blog_category_id)
#related already includes all posts, you need to remove the current post from the list or skip it in the iteration:
Exclude the current one before iterating
<% #related[#post.blog_category_id].reject { |post| post == #post }&.each do |rel| %>
or just skip the iteration if the current one is the post in question:
<% #related[#post.blog_category_id]&.each do |rel| %>
<% next if rel == #post %>
Try using .offset(1). Something like:
#related = Post.friendly.all.group_by(&:blog_category_id).offset(1)
or
#related = Post.friendly.all.group_by(&:blog_category_id).order("created_at desc").offset(1)

Rails 5 ActionView::Helpers capture method

I'm new in ruby on rails, and I want to practice it.
I'm stuck when I want to include a view into antoher view.
I want by doing that to have my posts into another view than of posts/index
posts/index
method:
def index
#Posts = Post.all
end
view:
<% #posts = capture do %>
<% #posts.each do |post| %>
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
<% end %>
<% end %>
pages/index
<h1> Index Of another pages </h1>
<%= #posts %>
If you want to force your index action to render another view, then go with follow code:
def index
#Posts = Post.all
render 'pages/index'
end
Correct me if I haven't get you
It sounds to me like you need to save the reusable view code as a partial, and render it all places it's required.
To use a partial, save it down with an underscore prefix, i.e. _posts.html.erb.
This can then be rendered using:
<%= render 'path/to/posts' %>
You'll likely need to pass in the posts variable to the partial, as in the following:
<%= render 'path/to/posts', posts: #posts %>
And the change your view to use posts rather than #posts.
Update:
The result of capture is assigned to #posts, although this variable still wouldn't be available in another template - rather to be used again on the same page
Based on what you're saying about the project's structure, it sounds like you'd need the following:
in app/views/posts/_posts.html.web
<% #posts.each do |post| %>
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
<% end %>
In both controllers' index action:
#posts = Post.all
In the posts/index view:
<%= render 'posts' %>
In the pages/index view:
<%= render 'posts/posts' %>
I don't want to confuse things, but Rails has a little magic in there where -
alternatively - you can define a partial _post.html.erb as follows:
<h3>
<%= post.title %>
</h3>
<p>
<%= post.content %>
</p>
And simply call <%= render #posts %> in each view. This would be the best 'Railsy' way of doing things.
Let me know how you get on!

Cant get a random post to display on rails blog

I've been trying to get a single random blog post to display for my rails blog on the home page. This is the code I used from another post on stackoverflow
def index
#post = Post.offset(rand(Post.count)).first
end
For Views I tried everything from #post.each do |post| to <%= #post %>. and it still is not displaying one random post.
#post = Post.offset(rand(Post.count)).first query would return a single random record from posts table so you cannot call each on it (#post.each) as it is not a collection.
To display that random post in your view, use
<%= #post.try(:field_name) %>
where replace field_name with the field from posts table that you would like to display.
For example: If you have title and body fields in posts table that you would like to display in index view, use:
<%= #post.try(:title) %>
<%= #post.try(:body) %>
using try so that if #post is nil i.e., if there are no records in posts table, you wouldn't receive any error on your page.
UPDATE
To access the attributes of each post from a collection #posts set using
#posts = Post.all
You would need to iterate over the collection as below:
<%= #posts.each do |post| %>
<%= post.try(:title) %>
<%= post.try(:body) %>
<% end %>

nested attribute pagination error (kaminari)

I'm pretty sure that this is a simple fix but I'm not seeing it. I have an app where I'd like to show a music_videos comments. Below are my controllers:
def show
#music_video = MusicVideo.find(params[:id])
#comment = Comment.new
#comments = #music_video.comments.page(params[:page]).per(3)
end
The above is my music video controller.
def create
#music_video = MusicVideo.find(params[:music_video_id])
#comment = #music_video.comments.build(comment_params)
if #comment.save
flash[:notice] = "Comment Submitted"
redirect_to music_video_path(#music_video)
else
render 'music_videos/show'
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
redirect_to root_path, notice: "Comment Deleted"
end
private
def comment_params
params.require(:comment).permit(:body)
end
Above is my comments controller
Finally my show page:
<div class="comments_row">
<% #music_video.comments.each do |comment| %>
<% if user_signed_in? && current_user.admin? %>
<p class="comment"><%= comment.body %></p>
<%= link_to 'Delete Comment', music_video_comment_path(#music_video,comment),
method: :delete %>
<% else %>
<p class="comment"><%= comment.body %></p>
<% end %>
<%end%>
</div>
<%= paginate #comments %>
I'm pretty sure something is wrong with my controllers, but I'm not sure exactly what it is. #comments is in the correct controller (MusicVideo) within the correct CRUD operation (show). Currently I have six comments in a particular show page and the pagination shows up just fine but the six comments are not paginated. Any thoughts?
EDIT-------------
I figured out one the problem but stumbled on a new one. I figured out that in my controller I am declaring #comments = pagination etc. etc. when in my views there is no #comments to paginate. The problem is now that when I use
<%= paginate #comment %>
the code will break.the problem now that I'm having is what variable to paginate. Trying this code will also break
<%= paginate #music_video.comments %>
Any recommendations?
I set up a test application using the kaminari gem for pagination. This is what my my music video controller's show action looks like:
def show
#music_video = MusicVideo.find(params[:id])
#comments = #music_video.comments.page(params[:page]).per(3)
end
And here is what my show view looks like:
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong> <%= #music_video.name %>
</p>
<% #comments.each do |comment| %>
<p>
Comment: <%= comment.text %>
</p>
<% end %>
<%= paginate #comments %>
<%= link_to 'Edit', edit_music_video_path(#music_video) %> |
<%= link_to 'Back', music_videos_path %>
It is working and the pagination is showing up for me.
I think one thing i see directly is that you should use <% #comments.each do |comment| %> instead of <% #music_video.comments.each do |comment| %> because the way you have it now it will display all comments for the video regardless of what page you are on. If you had 6 comments and wanted 3 per page you would see the pagination with the two pages because you're running your pagination based off of #comments and you would end up seeing all 6 comments on both pages because you're doing your .each with #music_videos.comments.each.
So, at least using #comments in both places would be a start. And make sure you're using <%= paginate #comments %> for the pagination. If you use this in your controller and view what do you get? Do you see any comments?
Also, Ryan Bates has a great screencast on Kaminari as well: http://railscasts.com/episodes/254-pagination-with-kaminari (that site is a great resource for rails questions)

Rails AJAX Search form reloading page

New to AJAX and search. I feel like I'm an inch away on this one, but I'm not sure what to fix. Also, my controller looks really hacky to me right now.
At any rate, I'm trying to create a search that allows users to search through blog posts on my page using AJAX. Here are the (relevant parts of the) parts:
posts_controller.rb
def show
#posts = Post.all.reverse
#post = Post.find(params[:id])
#link_num = 10
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to #post }
end
end
def search
#link_num = 10
#posts = Post.all.reverse
#post = Post.find(params[:id])
#The including function returns the search results
#search = Post.first.including(params[:term])
render 'show'
end
What strikes me as "hacky" here is that I repeat all the variable assignments (there are others I didn't show cause they're not relevant). Shouldn't an AJAX call ideally not have to redefine/reload all these variables? Also, I have to pass :id to my search action through a hidden field. This feels weird/wrong to me.
show.html.erb
<h1 class="squeeze">Recent Posts</h1>
<%= form_tag("/search", method: "get", class: "search") do %>
<%= text_field_tag(:term, '', placeholder: "Search posts:") %>
<%= hidden_field_tag(:id, #post.id) %>
<%= submit_tag("Search", class: "btn search_button", remote: true) %>
<% end %>
<% if !#search%>
<ul>
<% #posts.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #posts.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing #{#link_num} most recent posts." %></h5>
<h5>Search to narrow results.</h5>
</div>
<% end %>
</ul>
<% elsif #search.empty? %>
<h3>Term not found!</h3>
<% else %>
<ul>
<% #search.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #search.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing first #{#link_num} relevant hits." %></h5>
<h5>Narrow search for more specific results.</h5>
</div>
<% end %>
</ul>
<% end %>
routes.rb
match '/search', to: 'posts#search'
Currently, the search itself works fine, with three major problems:
The aforementioned messiness of my Controller.
The fact that the whole page reloads. Isn't that the opposite of what AJAX is supposed to do? How can I get it to reload just the list of links?
The URL. It's super messy (i.e "/search?utf8=✓&term=limits&id=11&commit=Search"). I'd ideally have it remain untouched by the search, but if that's not possible, maybe just something like "/search?=". How's that done?
Based on the comment here is basic logic to make the function work(Sorry for no real code as that is too time consuming)
In controller you make a method say "search". The method need an argument which is the phrase to search. It gets the result from db and respond to JSON only with the result.
In template you have a search form.
In JS, you listen the event of user clicking the submit button, catch the characters they write, and handle it to ajax function.
Write Ajax code, preferred using jQuery's ajax(). Basically use ajax() to send the typed characters to controller method in #1 as argument. Then ajax() will get the response(the search result) from server.
Update the result in DOM. You can either add a new div to show search result, or replace current main content div to show result.

Resources