How to limit someone to deleting their own comment in Rails? - ruby-on-rails

I am very new to Rails. I completed a tutorial here that walks you through the steps of creating a blog using it.
Part of the tutorial shows you how to create a controller that allows users to add comments to an article. I am trying to modify it so that users can only delete their own comments (and not others' comments).
Question:
Is there a way to modify the code so that way you can limit users to deleting their own comments? Any resources/tutorials are welcome too. I really just have no clue on how to start.
I feel like the right way to go is to mark the user some way when they submit the comment. Save that information in the database, and then check that information when someone goes to delete a comment. But I can't think of a way to do that without trying to build a full on log in system for users.
Code:
Here is the code from the tutorial:
Database Migration:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :commenter
t.text :body
t.references :article, index: true, foreign_key: true
t.timestamps null: false
end
end
end
Controller:
class CommentsController < ApplicationController
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
Template:
<p>
<strong>Title:</strong>
<%= #article.title %>
</p>
<p>
<strong>Text:</strong>
<%= #article.text %>
</p>
<h2>Add a comment:</h2>
<%= form_for([#article, #article.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
Delete Comment:
class CommentsController < ApplicationController
  def create
    #article = Article.find(params[:article_id])
    #comment = #article.comments.create(comment_params)
    redirect_to article_path(#article)
  end
 
  def destroy
    #article = Article.find(params[:article_id])
    #comment = #article.comments.find(params[:id])
    #comment.destroy
    redirect_to article_path(#article)
  end
 
  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end
I found a similar question here, but there wasn't an answer that worked.

In CommentsController Edit your destroy method like below :
def destroy
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
if #comment.user.id == current_user.id
flash[:success] = "Comment Deleted Successfully!"
#comment.destroy
else
flash[:error] = "You can only delete your own comments!"
end
redirect_to article_path(#article)
end
Add a migration to add user_id to the comment table :
class AddUserIdToComments < ActiveRecord::Migration
def change
add_column :comments, :user_id, :integer
end
end
Comment & User Model should be like below to track the user from comment :
class User < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
end
View:
<p>
<strong>Title:</strong>
<%= #article.title %>
</p>
<p>
<strong>Text:</strong>
<%= #article.text %>
</p>
<h2>Add a comment:</h2>
<%= form_for([#article, #article.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :commenter %>
<%= f.hidden_field :user_id, current_user.id %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
In Comment Controller change comment_params
def comment_params
params.require(:comment).permit(:commenter, :body, :user_id)
end

Related

ForbiddenAttributesError in Rails 5

I am getting Forbidden Attributes Error even though I have used strong parameters in Rails. I have two models: Posts and Categories.
Here is my Post Controller:
class PostsController < ApplicationController
def index
#posts=Post.all
end
def new
#post=Post.new
#category=Category.all
end
def create
#post = Post.new(params[:post])
if #post.save
redirect_to posts_path,:notice=>"Post saved"
else
render "new"
end
end
def allowed_params
params.require(:post).permit(:title, :body, :category_id)
end
end
And here is my view for posts/new:
<%= form_for #post do |f| %>
<p>
<%= f.label :title %></br>
<%= f.text_field :title%><br/>
</p>
<p>
<%= f.label :body %></br>
<%= f.text_area :body%><br/>
</p>
<p>
<%= f.select :category_id, Category.all.collect{|x| [x.name,x.id]},{:include_blank =>"Select one"}%><br/>
</p>
<p>
<%= f.submit "Add Post" %>
</p>
<% end %>
But I am still getting Error.
You need to use allowed_params instead of params[:post]:
#post = Post.new(allowed_params)

redirect_to #article doesn't work. article_url not defined

As I said above. I use my code like this.
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
def new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
But it always doesn't work. I have no idea and other questions are no use.
This is my template.
<%= form_for :article,url: articles_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
My fault I mistyped resources in the the route.
resources :articles

Rails wrong number of arguments (1 for 0) #post.save

I have the following controller :
class PostsController < ApplicationController
def index
end
def new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
ANd my model is
class Post < ActiveRecord::Base
end
My new.html.erb page is
<h1> New post </h1>
<%= form_for :post, url:posts_path do |f| %>
<p>
<%= f.label :title %> <br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes :
Rails.application.routes.draw do
resources :posts
root "posts#index"
end
I keep getting this error :
ArgumentError in PostsController#create
wrong number of arguments (1 for 0)
what did I do wrong here ?

params.require(:article).permit(:name, :story) not mapping to db

I'm learning Rails and I am working on a blog. I'm facing the problem that one of the fields of the form is not mapping to the database. When I save a new article the name maps to the db but not story. I end Up having a null column in the db.
My migration
class CreateArticles < ActiveRecord::Migration
def change
create_table :articles do |t|
t.string :name
t.text :story
t.timestamps
end
end
end
forms/new.html.erb
<h1>New Article</h1>
<%= form_for :article, url: articles_path do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :story %><br>
<%= f.text_area :story %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
controller
class ArticlesController < ApplicationController
def new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
def show
#article = Article.find(params[:id])
end
private
def article_params
params.require(:article).permit(:name, :story)
end
end
Uses debugger gem and check the params are passes correct it will be good if you can just share the devlopment.log

undefined method `reviews' for nil:NilClass

I'm trying to create a reviews model for company pages. For this I have:
Models
user.rb
has_many :reviews
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :reviews
end
My reviews controller is:
def create
#company = Company.find_by_slug(params[:id])
#review = #company.reviews.create(params[:review])
#review.save
redirect_to company_path(#company)
end
and I have this code in the company show page:
<% #company.reviews.each do |review| %>
<p>
<strong>Title:</strong>
<%= review.title %>
</p>
<p>
<strong>Avantage:</strong>
<%= review.avantage %>
</p>
<p>
<strong>Inconvenient:</strong>
<%= review.inconvenient %>
</p>
<% end %>
</br>
<%= form_for([#company, #company.reviews.build]) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :avantage %><br>
<%= f.text_area :avantage %>
</div>
<div class="field">
<%= f.label :inconvenient %><br>
<%= f.text_area :inconvenient %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, when I go to a specific company page and try to create a review for this company I'm getting this error message undefined method reviewsfor nil:NilClass
Instead of #company = Company.find_by_slug(params[:id]) use this code #company = Company.friendly.find(params[:company_id])
There are a couple of things you may find useful:
If you're using Rails 4, you may encounter a further problem. In the third line of your create method, you are using unsecure params directly in a .create call. Check out the Rails Guide page on "strong params".
If you implement strong parameters as mentioned above, you should probably deliberately omit the company_id field from the list of permitted params.
Assuming your users are allowed to write a review for any company in your system, it might be simpler for you to embed the company_id as a hidden field in your form. This would allow you to also simplify the controller method. For example:
# _form.html.erb
<%= form_for(#review) do |f| %>
<%= f.hidden_field :company_id, value: #company.id %>
...bla bla bla
<% end %>
Then, in your reviews_controller...
# reviews_controller.rb
def create
#review = Review.new(approved_params)
if #review.save
flash[:success] = 'Review created!'
else
flash[:error] = "Review wasn't saved"
end
#company = #review.company
redirect_to #company
end
def approved_params
params.require(:review).permit(:title, :avantage, :inconvenient, :company_id)
end
In your companies_controller, you should add this to your show method
# companies_controller.rb
def show
#company = Company.find(params[:id]
# add this line below...
#review = Review.new
end
I hope this helps.

Resources