ActiveModel::ForbiddenAttributesError Rails 4.1 - ruby-on-rails

I'm getting the following ActiveModel::ForbiddenAttributesError when creating a comment on my app.
The error message precise that the problem comes from line 7 in my Comments Controller file: #comment = #pin.comments.create(params[:comment])
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_user!
def create
#pin = Pin.find(params[:pin_id])
#comment = #pin.comments.create(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
def comment_params
params.require(:comment).permit(:body, :pin_id)
end
end
here is the comment model
class Comment < ActiveRecord::Base
belongs_to :pin
end
Any help with this error message?

You should replace this line with
#comment = #pin.comments.create(comment_params)
Also, putting pin_id in permitted parameters is unnecessary (since you create comment through #pin.comments association) and possibly unsafe (user could associate comment with other Pin).

Related

Error: ActiveModel::ForbiddenAttributesError in CommentsController#create

I try to create comments for post, it gives me this error
ActiveModel::ForbiddenAttributesError in CommentsController#create
ActiveModel::ForbiddenAttributesError
Extracted source (around line #6):
This is my comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
end
This is my comment model
class Comment < ActiveRecord::Base
belongs_to :post
end
This is my comment create table migration
class CreateComments < ActiveRecord::Migration
drop_table :comments
def change
create_table :comments do |t|
t.integer :post_id
t.integer :user_id
t.text :content
t.timestamps null: false
end
end
end
I hope you will help me.
Your comments_controller should look somewhat like this:
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
def comment_params
params.require(:comment).permit(:post_id, :user_id, :content)
end
And, I highly recommend you to read the Rails Official documentation for Strong Parameters.
It seems like you didn't register your strong parameter of comments.
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
def comment_params
params.require(:comment).permit(:post_id, :user_id, :content)
end
end
Do you have the params set in the file, it looks like you did not post the whole thing but if not, try something like this.
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
Then down at the bottom of the file make a private method
private
def comment_params
params.require(:comment).permit(:post_id,:user_id,:content)
end

What's the correct way of using the accepts_nested_attributes_for and the build methods for updating record in Rails?

I'm using Rails 4.1.4 on a Xubuntu machine. I have a Question model that has many alternativas (possible answers in my language), like this:
# question.rb
class Question < ActiveRecord::Base
has_many :alternativas, dependent: :destroy
validates_presence_of :text
accepts_nested_attributes_for :alternativas, reject_if: proc {|attributes| attributes[:texto].blank? }
end
# alternativa.rb
class Alternativa < ActiveRecord::Base
belongs_to :question
end
Question only has the :text attribute (string), and answer only the :texto attribute (also a string). I can create a question, but when I try to edit it, it edits only the question text, not the answers. New answers are created instead of the old ones being updated.
Also, as the :text field is required, when I leave it blank it redirects to the same page with the error message, but for some weird reason all the answers are doubled (if there is one answer when I submit the form, there will be 2 equal answers when it shows the error message).
So how can I solve this two problems? My guess is that I'm not using the build and the accepts_nested_attributes_for methods correctly, so here is my controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_filter :authorize
before_filter :verify_admin
def index
#questions = Question.all
end
def show
end
def new
#question = Question.new
#question.alternativas.build # I also tried 5.times { #question.alternativas.build } for 5 answers text fields
end
def edit
end
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:text, { alternativas_attributes: [:texto, :question_id] })
end
end
The problem is with your question_params. It should be like below
def question_params
params.require(:question).permit(:text, alternativas_attributes: [:id, :texto, :question_id])
end

Merit doesn't add points to user after create action

I've used this instructions for simply add score when a user creates a "solucion" (which is a kind of "answer" to a micropost). I have added the has_merit line to user.rb (user model).
I want to display the user points earned for that action at the show view.
show.html.erb (for solucion):
<h2><span class="red"><%= current_user.points %></span><br>Points</br></h2>
It displays 0 points...
point_rules.rb:
module Merit
class PointRules
include Merit::PointRulesMethods
def initialize
score 5, on: 'solucions#create'
end
end
end
When I create a solucion with the current_user (already saving the user_id index and identifier to solucion), This is what my rails server output shows...
Direct link to github gist:
https://gist.github.com/roadev/7b34fd67ab93c979fa48
Embed:
<script src="https://gist.github.com/roadev/7b34fd67ab93c979fa48.js"></script>
EDIT:
solucions_micropost.rb
class SolucionsController < ApplicationController
before_action :set_solucion, only: [:show, :edit, :update, :destroy]
def index
#solucions = Solucion.all
end
def show
end
def new
#solucion = current_user.solucions.build
end
def edit
end
def create
#solucion = current_user.solucions.build(solucion_params)
respond_to do |format|
if #solucion.save
format.html { redirect_to #solucion, notice: 'Solucion was successfully created.' }
format.json { render action: 'show', status: :created, location: #solucion }
else
format.html { render action: 'new' }
format.json { render json: #solucion.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #solucion.update(solucion_params)
format.html { redirect_to #solucion, notice: 'Solucion was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #solucion.errors, status: :unprocessable_entity }
end
end
end
def destroy
#solucion.destroy
respond_to do |format|
format.html { redirect_to solucions_url }
format.json { head :no_content }
end
end
private
def set_solucion
#solucion = Solucion.find(params[:id])
end
def current_micropost
#solucion = microposts.find_by(id: params[:id])
end
def solucion_params
params.require(:solucion).permit(:solucion, :image, :micropost_id)
end
end
user.rb:
class User < ActiveRecord::Base
has_many :dreams
has_many :microposts
has_many :solucions
has_merit
end
I had a problem with a migration when I installed the merit gem.

how do I write create method in the controller for a submission form that uses a join table?

I'm trying to create a form that allow called submits. I've got all the appropriate MVC created. I've then created a model called questions that works and am using active admin to allow admin users to add new questions to the form as they see fit. When I test submitting the form I get this error
undefined method `each' for nil:NilClass
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
Here's my submits controller:
class SubmitsController < ApplicationController
before_action :set_submit, only: [:show, :edit, :update, :destroy]
def index
#submits = Submit.all
end
def show
end
def new
#submit = Submit.new
#questions = Question.all
end
def edit
end
def create
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
respond_to do |format|
if #submit.save
format.html { redirect_to #submit, notice: 'Application was successfully created.' }
format.json { render :show, status: :created, location: #submit }
else
format.html { render :new }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #submit.update(submit_params)
format.html { redirect_to #submit, notice: 'Application was successfully updated.' }
format.json { render :show, status: :ok, location: #submit }
else
format.html { render :edit }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def destroy
#submit.destroy
respond_to do |format|
format.html { redirect_to submits_url, notice: 'Submit was successfully destroyed.' }
format.json { head :no_content }
end
end
Here's my Submit and Question model:
Submit:
class Submit < ActiveRecord::Base
has_and_belongs_to_many :questions
belongs_to :user
end
Question:
class Question < ActiveRecord::Base
has_and_belongs_to_many :submits
end
I'm sure it's some kind of syntax error in my controller but I don't know what. Still pretty new to using join tables. Any help/explanation would be very appreciated.
Thanks!
You don't need this
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
I don't see your submit params but if you add question ids to the permitted parameters then rails will build the entry in the join table on it's own.
def submit_params
params.require(:submit).permit(:user_id, question_ids: [])
end

undefined method `destroy' on Public Activity

User's can comment on a Screen and it's tracked by PublicActivity :
#comment.create_activity :create, owner: current_user, recipient: #comment.screen.user
and the comments are dependent: :destroy on the screen model.
But when i delete a screen, while the comments are deleted, the Record from PublicActivity for that comment still exists.
here's my Screens Controller:
def destroy
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy #<-- Heres the Problem
#screen.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
end
end
But upon deleting a Screen, i'm getting undefined methoddestroy' for nil:NilClass`.
I read on Railscast:
it was due to calling the create_activity method after the object had
been destroyed.
According to the gem maintainers, you simply have to assume the record
will be destroyed, and call create_activity before the destroy
What am i missing?
Informations below
screen.rb
belongs_to :user
has_many :comments, :dependent => :destroy
comment.rb
belongs_to :user
belongs_to :screen
screens_contoller.rb
def create
#screen = current_user.screens.build(screen_params)
respond_to do |format|
if #screen.save
format.html { redirect_to #screen, notice: 'You successfully uploaded your Screenshot.' }
format.json { render action: 'show', status: :created, location: #screen }
current_user.add_points(2, 'Points for Uploading a Screenshot')
else
format.html { render action: 'new' }
format.json { render json: #screen.errors, status: :unprocessable_entity }
end
end
end
def destroy
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
#screen.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
current_user.substract_points(1, "Substraction for Deleting a Screenshot")
end
end
comments_controller.rb
def create
#screen = Screen.find(params[:screen_id])
#comment = current_user.comments.build(comment_params)
#comment.screen_id = #screen.id
respond_to do |format|
if #comment.save
# Create Record for Public Activity
#comment.create_activity :create, owner: current_user, recipient: #comment.screen.user
format.html { redirect_to #screen, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#comment.destroy
respond_to do |format|
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
format.html { redirect_to :back }
format.json { head :no_content }
end
end
That's how my Screen Controller Destroy Action looks like right now:
def destroy
#screen = current_user.screens.find(params[:id])
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
#screen.destroy
current_user.substract_points(1, "Substraction for Deleting a Screenshot")
respond_to do |format|
format.html { redirect_to root_path }
end
end
Again the same error:
This isn't tested, but this is what I think you should do.
First you can remove the references to activities in your screens_controller#destroy
Then in your comments_controller#destroy
#comment = current_user.comments.find(params[:id])
#activity = PublicActivity::Activity.find_by(trackable_id: (params[:id]), trackable_type: controller_path.classify)
#activity.destroy
#comment.destroy
Should be outside of your respond to block
Next in your comments model you should do something like this:
#comment.rb
private
before_destroy :find_and_destroy_comments
def find_and_destroy_comments
activity = PublicActivity::Activity.find_by(trackable_id: self.id, trackable_type: self.class.name)
if activity.present?
activity.destroy
end
end
calling the before_destroy method overrides the default ruby destroy method that is called during dependent: :destroy
Let me know if this works, but It should.

Resources