Implementing most recent post in my index.html.erb Rails template - ruby-on-rails

I've been putting the finishing touches on my app all day with the help of some useful answers here and would like to know how this feature can be executed. I have an idea set up in my post_controller file where I want to show the top 10 most recent posts created based on the date that they were created. I also plan on doing this for my comments as well laster on. I am showing all users post in the views/post/index.html.erb file. I wrote this line of code in the posts_controller: posts = Post.order('created_at DESC').limit(10). I've searched here thoroughly but don't understand how some other users got this to work, any insight? Thanks in advance.
posts_controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :vote]
before_action :require_user, only: [:new, :create, :edit, :update, :vote]
before_action :require_creator, only:[:edit, :update]
def index
posts = Post.order('created_at DESC').limit(10)
#posts = Post.all.page(params[:page]).per_page(10)
end
def show
#comment = Comment.new
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.creator = current_user
if #post.save
flash[:notice] = "You created a post!"
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
flash[:notice] = "You updated the post!"
redirect_to post_path(#post)
else
render :edit
end
end
def vote
Vote.create(voteable: #post, creator: current_user, vote: params[:vote])
respond_to do |format|
format.js { render :vote } # Renders views/posts/vote.js.erb
end
end
private
def post_params
params.require(:post).permit(:url, :title, :description)
end
def set_post
#post = Post.find(params[:id])
end
def require_creator
access_denied if #post.creator != current_user
end
end

The posts variable you've declared in your index action will not be available in your view. What you need to do is update the line where you're retrieving the posts using instance variable as follows:
def index
#posts = Post.page(params[:page]).order('created_at DESC').per_page(10)
end

Related

Ruby on Rails: destroy function not deleting item

I have a user and article model where a user can have many models, and have restricted the delete function to user or admin. yet when i attempt to destroy the article, i get the following error:
undefined method `user' for nil:NilClass
and its pointing to this private function in my articles controller:
def require_same_user
if current_user != #article.user and !current_user.admin?
flash[:danger] = "You can only edit or delete your own articles"
redirect_to root_path
end
end
this is my whole controller file:
class ArticlesController < ApplicationController
before_action :set_article, only: [:edit, :update, :show]
before_action :require_user, except: [:index, :show]
before_action :require_same_user, only: [:edit, :update, :destroy]
def index
#articles = Article.paginate(page: params[:page], per_page: 5)
end
def show
end
def new
#article = Article.new
end
def edit
end
def update
#article.update(article_params)
if #article.save
flash[:success] = "Article successfully updated!"
redirect_to article_path(#article)
else
flash[:danger] = "Sorry, try again..."
render :edit
end
end
def create
#article = Article.new(article_params)
#article.user = current_user
if #article.save
flash[:success] = "New article created"
redirect_to articles_path
else
flash[:danger] = "Sorry, invalid values"
render :new
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
flash[:success] = "Article deleted"
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:name, :title, :description)
end
def set_article
#article = Article.find(params[:id])
end
def require_same_user
if current_user != #article.user and !current_user.admin?
flash[:danger] = "You can only edit or delete your own articles"
redirect_to root_path
end
end
end
the articles and users exist in db so what could this be? thanks in advance
You're setting the article using the set_article function, but in the case of the require_same_user function, it doesn't know what's the value of #article; so in that case, the value is nil, as it's not in the scope, nor figure as an instance variable created before.
def require_same_user
# Here there's no #article, so it's evaluated as nil,
# and nil doesn't have a method user.
if current_user != #article.user ...
...
One approach could be to set the set_article also to be executed before the require_same_user does it.
before_action :set_article, only: %i[edit update show require_same_user]
You could also divide your code in smaller pieces to be used back again whenever you need it:
def require_same_user
redirect_to_root_path unless article_owner? && admin?
end
def redirect_to_root_path
flash[:danger] = 'You can only edit or delete your own articles'
redirect_to root_path
end
def admin?
current_user.admin?
end
def article_owner?
current_user == #article.user
end
Make sure set_article runs before destroy action.
In your controller:
before_action :set_article, only: [:edit, :update, :show, :destroy]

How To Have A Blog Where Users Can Only Edit Posts For A Limited Time in Ruby on Rails

I've made a very simple blog where users can Create, Edit and Delete posts however I want to add functionality where users can only Edit for a limited time (say 3 days). My understanding of Ruby is not strong enough to know how to do this so any help is appreciated.
This is my Notes (my name for Posts) controller
class NotesController < ApplicationController
before_action :find_note, only: [:show, :edit, :update, :destroy]
def index
#notes = Note.where(user_id: current_user)
end
def show
end
def new
#note = current_user.notes.build
end
def create
#note = current_user.notes.build(note_params)
if #note.save
redirect_to #note
else
render 'new'
end
end
def edit
end
def update
if #note.update(note_params)
redirect_to #note
else
render 'edit'
end
end
def destroy
#note.destroy
redirect_to notes_path
end
private
def find_note
#note = Note.find(params[:id])
end
def note_params
params.require(:note).permit(:title, :content)
end
end
I assume somewhere in the edit method I need to write a rule for restricting the ability to edit posts to only 3 days, using the created_at function somehow? I'm just at a loss as to exactly how to do this.
Any help is appreciated.
Perfect solution for that is :before_filter
class NotesController < ApplicationController
before_filter :check_time!, only: [:edit, :update]
def edit
end
def create
end
private
def check_time!
if Time.now() > #note.created_at + 3.days
flash[:danger] = 'Out of 3 days'
redirect_to note_path(#note)
end
end
end

Special Access To Edit Pieces Model Devise User ID 1

I am using devise, and have a pieces model in my Ruby on Rails web app. A user has_many pieces. Right now, in my pieces controller, I have a method called correct_user, which allows only users who own the pieces to edit and destroy them. I want to add a line to this method which allows the user with a devise user id of 1 to be able to edit and destroy anyone else's pieces (if current_user.id ==1, then allow the edit/destroy actions). I have tried a few combinations, but I keep getting errors.
Here is my pieces controller: (the correct_user method is towards the end)
class PiecesController < ApplicationController
before_action :set_piece, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
respond_to :html
def index
#pieces = Piece.all
respond_with(#pieces)
end
def show
respond_with(#piece)
end
def new
#piece = current_user.pieces.build
respond_with(#piece)
end
def edit
end
def create
#piece = current_user.pieces.build(piece_params)
flash[:notice] = 'Piece was successfully created.' if #piece.save
respond_with(#piece)
end
def update
flash[:notice] = 'Piece was successfully updated.' if #piece.update(piece_params)
respond_with(#piece)
end
def destroy
flash[:notice] = 'Piece was successfully deleted.' if #piece.destroy
respond_with(#piece)
end
private
def set_piece
#piece = Piece.find(params[:id])
end
def correct_user
#piece = current_user.pieces.find_by(id: params[:id])
redirect_to pieces_path, notice: "Access Denied! Not authorized to edit this piece." if #piece.nil?
end
def piece_params
params.require(:piece).permit(:title, :image, :genre, :size, :price, :description, :status)
end
end
Thanks guys!
In correct_user, change the conditional on redirect_to to and return if #piece.nil? and current_user.id != 1, then add a new line below that: #piece = Piece.find(params[:id]) if current_user.id == 1, which will only run if the redirect_to ... and return does not.
(Also, you have current_user.pieces.find_by(id: ...), which can be just .find(...) for simplicity.)

Rails 4 models managed through nested form -- do I need child controllers?

My models are Survey, Question, and Choice, which are nested under SurveysController in views, including by nested forms. In other words, my path is never '/questions/foo', but rather it is always something like: '/surveys', 'surveys/:id', '/surveys/:id/edit' OR nested as '/surveys/:id/questions'.
If this is the case, are my QuestionsController and ChoicesController unnecessary? There aren't any behind the scenes calls/redirects to create/update/delete actions in these child controllers, right?
Just trying to pare down excess code that isn't being used. New to Rails, so thanks for help here.
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
before_action :set_question_formats, only: [:show, :new, :create, :edit, :update]
def index
#surveys = current_user.surveys
end
def show
if #survey.questions.any?
#questions = #survey.questions
end
end
def new
#survey = QuestionSet.new
3.times do
question = #survey.questions.build
4.times { question.choices.build }
end
end
def edit
end
def create
#survey = current_user.surveys.build(survey_params)
respond_to do |format|
if #survey.save
#survey.remember
session[:survey_id] = #survey.id
format.html { redirect_to #survey,
notice: "Success!" }
else
format.html { render action: 'new' }
end
end
end
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
else
format.html { render action: 'edit' }
end
end
end
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url }
end
end
private
def set_survey
#survey = Survey.find(params[:id])
session[:survey_id] = #survey.id
end
def survey_params
params.require(:survey).permit(:id, :title,
questions_attributes: [:id, :content, :_destroy, :question_format_id,
choices_attributes: [:id, :content, :_destroy]])
end
end
Ok, the QuestionsController is the active controller when questions
are nested under surveys as in '/surveys/:id/questions'.
Other than this (scoped questions#index) action, the
SurveysController is in charge, which takes care of
create/update/delete actions for itself and nested associations,
questions and choices.
Therefore, from my testing thus far, it appears that 1) the
ChoicesController is entirely unnecessary, 2) QuestionsController
does minimal duty, as in the given context and 3) SurveysController
is fully RESTful.

Displaying most recent comments in my def show action

I am having a bit of trouble displaying the most recent created comments based from the time/date that they were created in my views/post/show.htmlerb file. I just got my posts_controller to display the most recent created posts from the def index action but now in my def show action the following code doesn't work:
#comment_date_order = Comment.find(params[:id]).comments.order('created_at DESC')
this is my full posts_controller.rb file:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :vote]
before_action :require_user, only: [:new, :create, :edit, :update, :vote]
before_action :require_creator, only:[:edit, :update]
def index
#posts = Post.page(params[:page]).order('created_at DESC').per_page(10)
end
def show
#comment = Comment.new
#comment_date_order = Post.find(params[:id]).comments.order('created_at DESC')
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.creator = current_user
if #post.save
flash[:notice] = "You created a post!"
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
flash[:notice] = "You updated the post!"
redirect_to post_path(#post)
else
render :edit
end
end
def vote
Vote.create(voteable: #post, creator: current_user, vote: params[:vote])
respond_to do |format|
format.js { render :vote } # Renders views/posts/vote.js.erb
end
end
private
def post_params
params.require(:post).permit(:url, :title, :description)
end
def set_post
#post = Post.find(params[:id])
end
def require_creator
access_denied if #post.creator != current_user
end
end
comments_controller.erb file:
class CommentsController < ApplicationController
before_action :require_user
def create
#post = Post.find(params[:post_id])
#comment = Comment.new(params.require(:comment).permit(:body))
#comment.post = #post
#comment.creator = current_user
if #comment.save
flash[:notice] = "Your comment was created!"
redirect_to post_path(#post)
else
render 'posts/show'
end
end
def edit
#comment = Comment.find(params[:id])
#post = Post.find(params[:post_id])
end
def update
#comment = Comment.find(params[:id])
if #comment.update(comment_params)
flash[:notice] = "You updated your comment!"
redirect_to post_path(#post)
else
render :edit
end
end
private
def comment_params
params.require(:comment).permit(:body)
end
def set_comment
#comment = Comment.find(params[:id])
end
end
First you would need a relation between Post and Comment if you dont already.
I would just create a def in the Post model.
class Post < ActiveRecord::Base
has_many :comments
def newest_comments
self.comments.order('created_at DESC')
end
end
That way you could also make a oldest_post method and uses it directly in the view
<%= #post.newest_post.each do |comment| %>
Also as best practice. Try and not to create too many instance vars in your controller. Remember fat models, skinny controllers.

Resources