I'm making a blog type site, and I'd like the posts to be displayed newest first(descending order) Ive tried a few different things and haven't been able to figure it out. This is my current code:
post.html.erb
<%= #posts.each do |post|%>
<div>
<p><%= avatar_for(post.user, size: 40) %>
<%= link_to post.username, post.user %></p>
<h2>
<%= link_to post.title, post %>
</h2>
</div>
<% end%>
post controller
class PostsController < ApplicationController
before_action :authenticate_user!
def posts
#posts = Post.all.order("created_at DESC")
end
def new
#post = Post.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to post_path(#post)
else
render :new
end
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :body, :all_tags)
end
end
I believe, based on the Guide, that the syntax you're looking for is:
Post.order(created_at: :desc)
See if that works for you.
This should be #posts as you are calling #posts in you post.html.erb to retrieve and display all the posts:
def posts
#posts = Post.all.order("created_at DESC")
end
The method should look like
def posts
# Plural #posts
#posts = Post.all.order(created_at: :desc)
end
Just a small fix, in your posts method you're declaring #post variable but in the ERB file you're calling #posts.
That should be giving you a Nil error. Declare #posts (plural), and then your ERB file with better indentation:
<%= #posts.each do |post| %>
<div>
<p>
<%= avatar_for(post.user, size: 40) %>
<%= link_to post.username, post.user %>
</p>
<h2>
<%= link_to post.title, post %>
</h2>
</div>
<% end%>
In case this question hasn't been answered yet:
It looks like the problem is coming from the name of the method in your PostsController.
You're expecting to have access to #posts from a method called posts, but your file name for the view you're trying to render is post.html.erb. I believe it should be posts.html.erb.
Why not call it index? That's the Rails convention.
As others have said, the query is correct. Hope this helps.
Related
I'm not really sure how to quote this question, but I'm making a clone of Reddit in Ruby on Rails.
On the index page I am displaying all of the posts I have in the table "Posts". But when I display them all, at the end of the last post a text shows up which is wrapped in square brackets and contains all of the information from the table. I just want to know how to remove this text.
Picture of problem
This is the code used to display the post:
<%= #posts.each do |post| %>
<div class="card p-3">
<small class="mb-2"><strong><%= link_to "s\\" + post.sub.name, sub_path(post.sub) %></strong> Posted by <%= link_to "u\\" + post.user.username, profile_path(post.user.username) %> <%= time_ago_in_words post.created_at %> ago</small>
<h4><%= link_to post.title, sub_post_path(post.sub, post) %></h4>
<p><%= truncate post.body, length: 200 %></p>
</div>
<% end %>
My posts controller:
class PostsController < ApplicationController
before_action :authenticate_user!, except: [ :index, :show ]
before_action :set_post, only: [:show]
before_action :auth_subscriber, only: [:new]
def index
#posts = Post.all
end
def show
end
def new
#sub = Sub.find(params[:sub_id])
#post = Post.new
end
def create
#post = Post.new post_values
#post.user_id = current_user.id
#post.sub_id = params[:sub_id]
if #post.save
redirect_to subs_path(#post.sub_id)
else
#sub = Sub.find(params[:sub_id])
render :new
end
end
private
def set_post
#post = Post.find(params[:id])
end
def auth_subscriber
unless Subscription.where(sub_id: params[:sub_id], user_id: current_user.id).any?
redirect_to root_path, flash: { danger: "You are not authorized to view this page" }
end
end
def post_values
params.require(:post).permit(:title, :body)
end
end
<% #posts.each do |post| %>
<div class="card p-3">
<small class="mb-2"><strong><%= link_to "s\\" + post.sub.name, sub_path(post.sub) %></strong> Posted by <%= link_to "u\\" + post.user.username, profile_path(post.user.username) %> <%= time_ago_in_words post.created_at %> ago</small>
<h4><%= link_to post.title, sub_post_path(post.sub, post) %></h4>
<p><%= truncate post.body, length: 200 %></p>
</div>
<% end %>
In ERB <%= is used to output the result of an expression to the buffer. #each in Ruby returns self so what you're seeing on the page is the result of implicitly calling #to_s on an array.
#each is always used for its side effects and not its return value. In the case of an ERB template each iteration writes to the buffer.
This can be somewhat hard to grasp but remeber that any plaintext in a template is written directly to the buffer - using each just does it n number of times.
Change <%= #posts.each do |post| %> for <% #posts.each do |post| %>, note the missing '=' in the second snippet.
When you include the '=' the output of .each is printed in the HTML, in this case the array of posts.
I'm taking up rails as a hobby but I'm still fairly new so apologies if this sounds ridiculous. I'm creating a board that can have many statuses. And each status can have many notes. However, this error comes up once I added the notes loop into the status loop on the view:
undefined method `notes' for nil:NilClass
Snippet of the boards/show.html.erb file:
<% #board.statuses.each do |status| %>
<div>
<h2><%= link_to status.name, status_url(status)%></h2>
<% #status.notes.each do |note| %>
<h2><%= link_to notes.content, note_url(note)%></h2>
<% end %>
<%= link_to 'New notes', new_note_path(#note) %>
</div>
<% end %>
I'm not sure if I'm doing something wrong within the controllers or the view though. I've been having a hard time figuring it out. I appreciate any help though!
notes_controller:
class NotesController < ApplicationController
def new
#note = Note.new
end
def create
Note.create(note_params.merge(status_id: current_user.id))
redirect_to boards_url
end
def delete
Note.find(params[:id]).destroy(note_params)
end
def update
Note.find(params[:id]).update(note_params)
end
def note_params
params.require(:note).permit(:status_id, :content)
end
end
statuses_controller:
class StatusesController < ApplicationController
def new
#status = Status.new
end
def create
Status.create(status_params.merge(board_id: current_user.id))
redirect_to :root
end
def delete
Status.find(params[:id]).destroy(status_params)
end
def update
Status.find(params[:id]).update(status_params)
end
def show
#status = Status.find(params[:id])
end
def status_params
params.require(:status).permit(:board_id, :name)
end
end
Any more information required then let me know. Thank you. :)
I'm thinking it should look more like:
<% #board.statuses.each do |status| %>
<div>
<h2><%= link_to status.name, status_url(status)%></h2>
<% status.notes.each do |note| %>
<h2><%= link_to notes.content, note_url(note)%></h2>
<% end %>
<%= link_to 'New notes', new_note_path(#note) %>
</div>
<% end %>
So that you're using the notes from the status in a given loop.
The error you're getting is because in this line <% #status.notes.each do |note| %> the view is expecting to be passed #status object from the show action in the board's controller. Since you aren't passing that #status, it's nil and nil doesn't have the method notes.
As #jvillian pointed out, it should be <% status.notes.each do |note| %> because you want to get the notes from the statuses you're iterating over with each in this line: <% #board.statuses.each do |status| %>
I'm building simple web app where people can share their thought / pictures / so on. It has just two controllers Post, and nested in it Comments. Generally, at the moment all works perfectly, users can add, edit and delete posts the same way as comments. The thing I'm trying to do, and have big troubles with, is possibility to Edit comments without redirecting to the Edit Comment View - so to be able to do it from the "posts#show" level, the same way as comments actually are being created. I think it just would look much more nicer... Here are my:
posts_controller.rb
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all.order(created_at: :desc)
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#comments = #post.comments
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :description)
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :find_post, only: [:create, :edit, :update, :destroy]
def create
#comment = #post.comments.create(comment_params)
if #comment.save
redirect_to #post
else
render 'new'
end
end
def edit
#comment = #post.comments.find(params[:id])
end
def update
#comment = #post.comments.find(params[:id])
#comment.update_attributes(comment_params)
if #comment.save
redirect_to #post
else
render 'edit'
end
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to #post
end
private
def find_post
#post = Post.find(params[:post_id])
end
def comment_params
params.require(:comment).permit(:content)
end
end
View show.html.haml - for post
%h1 Show page
%h3= #post.title
%p= #post.description
=link_to "Edit memory", edit_post_path
=link_to "Delete memory", post_path, method: :delete
%h4 Share your thoughts about the memory
- #comments.each do |comment|
%p= comment.content
=link_to "Edit thought", edit_post_comment_path(#post, comment)
=link_to "Delete thought", post_comment_path(#post, comment), method: :delete
= simple_form_for([#post, #post.comments.build]) do |c|
= c.input :content
= c.submit "Share thought"
View edit.html.haml - for comments (the one I'd like to get rid of / nest somehow to the view shown above)
= simple_form_for([#post, #comment]) do |c|
= c.input :content
= c.submit "Update thought"
I believe there is a simple solution, however despite the fact that I've been reading a lot about possible solution, for a newbie like me it's still difficult to figure out how this should be programed.
The terminology you're looking for is in-place editing, or inline editing
You'll either need a form or JQuery plugin to make any comment written by current_user (assuming you're using Devise) editable.
I've done this a little (you can sign up for free here, click "profile" and then edit the description):
--
The way you'd want to do it is something like this:
#app/assets/javascripts/application.js
# include x-editable scripts
$(".editable).editable([..options..]);
#app/views/posts/index.html.erb
<% #posts.each do |post| %>
<%= post.body %>
<% post.comments.each do |comment| %>
<% if comment.author == current_user %>
<%= content_tag :div, comment.body, class: "editable" %>
<% end %>
<% end %>
<% end %>
I've forgotten how we implemented the provided example; x-editable seems to be the rage now.
Here's how it works:
Include X-Editable (or other plugin) in your app
X-Editable will check for the presence of a .class or #id on an element
Providing such an element will allow X-Editable to make it editable
X-Editable then sends the completed request to the server, acting as Ajax
Looks like there's an x-editable-rails gem you can use:
#Gemfile
gem `x-editable-rails`
#app/assets/javascripts/application.js
#= require editable/bootstrap-editable
#= require editable/rails
#app/views/posts/index.html.erb
<% #posts.each do |post| %>
<% post.comments.each do |comment| %>
<%= editable comment, :body if comment.author == current_user %>
<% end %>
<% end %>
when I attempt to run my code, I got the error above.
As you can see on the following image, the page posts/index leaves appear some information before the footer of the page :
I don't understand where it may come, because it's the only page where it appeared.
Here's my view :
<%= #post.each do |post| %>
<h1 class="Blog_post_title"><%= link_to post.title, post %></h1>
<p class="date"><%= post.created_at.strftime("%B, %d, %Y") %></p>
<p><%= image_tag post.landing_image.url , class: "landing_image_blog" %></p>
<p><%= post.body %></p>
<%= link_to post do %>
<div class="button12">Continuer la lecture</div>
<% end %>
<div class="border_grey_blog"></div>
<% end %>
</div>
<%= render "footer" %>
my posts_controller.rb:
class PostsController < ApplicationController
def index
#post = Post.all.order('created_at DESC')
end
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title,:title2,:title3,:title4,:title5,:title6,:title7,:title8,:title9, :body, :image,:image1,:image2,:image3,:image4,:image5,:image6,:image7,:image8, :landing_image, :some_text1, :some_text2, :some_text3, :some_text4, :some_text5, :some_text6, :some_text7, :some_text8, :some_text9, :some_text0))
redirect_to #post
else
render 'edit'
end
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to "/posts"
end
private
def post_params
params.require(:post).permit(:title, :body, :image,:image1,:image2,:image3,:image4,:image5,:image6,:image7,:image8, :landing_image, :some_text1, :some_text2, :some_text3, :some_text4, :some_text5, :some_text6, :some_text7, :some_text8, :some_text9, :some_text0, :title2,:title3,:title4,:title5,:title6,:title7,:title8,:title9)
end
end
Any idea ?
Your mistake is in the very first line of the view:
<%= #post.each do |post| %>
should be
<% #post.each do |post| %>
since <%= opens an expression tag that will display its content.
It looks like your outputting the result of #posts.each. Notice how you did this in your view:
<%= #post.each do |post| %>
# other code
<% end %>
This will actually output all the data in the array as a ruby object. If you want to change this to not output everything, you need to change it to
<% #post.each do |post| %>
# other code
<% end %>
This will now not return the #post.each in the html.
There are posts and comments form for each.
I'm trying to add a comment to every post through the form. It's all happening on the same page.
View file code:
<% #posts.each do |post| %>
<%=post.title%>
<%=post.text%>
<%post.comments.each do |com|%>
<h3> <%=com.content%> </h3>
<%end%>
<%= form_for post.comments.build do |f| %>
<p>comments:</p>
<%= f.text_area :content, size: "12x12" %>
<%=f.submit%>
<% end %>
<% end %>
Comments controller code:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
#comment.save
redirect_to root_path
end
It seems that program can not access to :post_id.
I have all associations in my models and :post_id in my db schema.
Github link for this app
You need to add <%= f.hidden_field :post_id %> in your form and permit :post_id in comment_params.
Also, you may want to reduce create method code to one line.
def create
Comment.create(comment_params)
redirect_to root_path
end
You need to permit :post_id for your strong parameters in the comments controller:
def comment_params
params.require(:comment).permit(:content, :post_id)
end
I found a problem.
The mistake is in searching by params[:post_id], while i need to by [:comment][:post_id] after adding the hidden_field