I am new to Ruby on Rails and I was trying to create a simple app when I ended up having a ActiveModel::ForbiddenAttributesError
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post =Post.new
end
def create
#post = Post.new(params[:post])
if #post.save
redirect_to post_path,:notice=>"success"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
private
def post_params
params.require(:post).permit(:Title, :content)
end
end
I have seen a similar error here but the solution for that did not fix my issue.
My version of rails is 4.2.0.
The error displayed is
You can't use that params[:post] hash (or any params[*] hash) directly in any mass-assignment method, you need to use a permit call so Rails knows you've checked it and to allow it.
So, change your Post.new to #post = Post.new(post_params)
Change #post = Post.new(params[:post]) to #post = Post.new(post_params).
I think that
def create
#post = Post.new post_params
if #post.save
flash[:success] = "Created new post"
redirect_to #post
else
render 'new'
end
end
def create
#post = Post.new(posts_params)
if #post.save
redirect_to post_path,:notice=>"success"
else
render "new"
end
end
private
def posts_params
params.require(:post).permit(:Title, :content)
end
Related
I am working on ruby on rails , I am trying to update my data
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to post_path,:notice =>"post has been updated"
else
render "edit"
end
end
it's not updating and the error coming is :-
ActiveModel::ForbiddenAttributesError in PostsController#update
Help me !
You cannot just update values based on params[:post], you will have to whitelist them using strong params.
Basically white post params like this in the controller
def post_params
params.require(:post).permit(:title, :description)
end
And then in the controller
def update
#post = Post.find(params[:id])
if #post.update_attributes(post_params)
redirect_to post_path,:notice =>"post has been updated"
else
render "edit"
end
end
private
def post_params
params.require(:post).permit(:title, :description)
end
I really want to start learning Rails best practices, especially following the "fat model, skinny controller" logic.
Say I have the following comment controller
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
#comment.user_id = current_user.id if current_user
#comment.save!
if #comment.save
redirect_to post_path(#post)
else
render 'new'
end
end
def edit
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
end
def update
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
if #comment.update(params[:comment].permit(:comment))
redirect_to post_path(#post)
else
render 'Edit'
end
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
private
def comment_params
params.require(:comment).permit(:comment)
end
What's a good place to start refactoring the code?
Immediately I think I an make the #post and #comment in both edit and update into a separate method, follow by calling a before_action on the method. But that is still putting all the code in the controller.
Are there any code that I can move to the model? If so, how should I structure them?
This code doesn't have much room for improvement, it's a basic crud, here's an example of a before_action like you suggested
before_action :load_post_and_comment, only: %i(edit update destroy)
def load_post_and_comment
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
end
And here a couple of other notes
def create
# ...
#comment.save!
if #comment.save
# ...
else
# ..
end
end
In this codition the you should remove the extra #comment.save! you only need to save once.
def update
# ...
if #comment.update(params[:comment].permit(:comment))
# ...
else
# ...
end
end
You already have the comment_params method, use it, because if you at any point add a new attribute to the comment, you'll update that method but you'll probably forget this part and you'll get werid errors till you notice that you need to permit here too.
If you want to really go all out with the skinny controller model, there is this gem: https://github.com/NullVoxPopuli/skinny_controllers
Where, you'd configure your CommentsController like so:
class CommentsController < ApplicationController
include SkinnyControllers::Diet
def create
if model.errors.present?
render 'new'
else
redirect_to post_path(model)
end
end
def update
redirect_to post_path(model)
end
# ... etc
private
def comment_params
params.require(:comment).permit(:comment)
end
end
I am trying to access the database and enter some info. it gives me an error saying "undefined local variable or method `post_params' for #< PostsController:0x00000005aad728>"
i know this has been answered here.
but i tried following what they did, and it just does not work, can someone help me with this?
class PostsController < ApplicationController
def index
#post = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_path, :notice => "Your post was saved"
else
render ="new"
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
end
Your end for create method is enclosing the private keyword and post_params method. Update it as:
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_path, :notice => "Your post was saved"
else
render ="new"
end
end # Add end here
private
def post_params
params.require(:post).permit(:title, :content)
end
end # Remove this end
You define your post_params method inside of create method. Move it outside of it and all will be working.
class PostsController < ApplicationController
def new
end
def create
#post = Post.new(params[:post])
#post.save
redirect_to #post
end
private
def post_params
params.require(:post).permit(:title, :text)
end
def show
#post = Post.find(params[:id])
end
def index
#posts=Post.all
end
end
You'll need to improve your code (you've set your index and show methods as private!):
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
def index
#posts=Post.all
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
As per the strong params documenation, you need to call the private method with your strong params inside in order to pass them
Because you're not using it.
Replace params[:post] with your method post_params.
Make post_params method as private method but not other method
private
def post_params
params.require(:post).permit(:title, :text)
end
Call it where you want to use like this.
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
My error message is "wrong number of arguments (0 for 1)"
for this line: #post = Post.destroy in my
PostsController#destroy
I have a model which is post.rb
My Posts Controller is here
class PostsController < ApplicationController
def new
#post = Post.new
end
def index
#posts = Post.all
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def post_params
params.require(:post).permit(:title, :text)
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, :text))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post = Post.destroy
redirect_to posts_path
end
end
In my view I have this code:
<%= link_to 'Destroy', post_path(post),
method: :delete, data: { confirm: 'Are you sure?' } %>
This is what it says I have for the parameters in the request
{"_method"=>"delete",
"authenticity_token"=>"Pzsnxv8pt+34KIKpYqfZquDv3UpihkINGSJxomMNsW4=",
"id"=>"3"}
What in the heck am I doing wrong??
You need to provide the ID to the destroy method:
Post.destroy(params[:id])
As stated here: http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-destroy
Here is your problem:
#post = Post.destroy
In Ruby you can destroy object in this way:
#post.destroy
Another tip: when you are using variables just inside model or controller, declare them as locals by not adding # in front of them and use # just for variables that you need to use globally. Learn more about that here:
In what circumstances should I use instance variables instead of other variable types?
Precisely what the error says.
You can:
Call destroy on an instance with no argument, e.g., #post.destroy
On the class with an id, e.g., Post.destroy(an_id)
I guess you wish to write:
#post.destroy