Our new Active Record models behave mostly the same as before, but with a couple of exceptions.
One glaring issue is that if we try to create a post right now, we get this:
ActiveModel::ForbiddenAttributesError in PostsController#create
This is because Active Record models distrust params
by default. There are security reasons for this, but we obviously want to allow some params
to be used, so we'll have to specify which ones to permit in our post controller:
### app/controllers/posts_controller.rb ###
class PostsController < ApplicationController
# ...
def create
@post = Post.new(post_params)
# ...
end
def update
if @post.update_attributes(post_params)
# ...
end
end
private
# ...
def post_params
params.require(:post).permit(:title, :body, :author)
end
end
Here we just create a post_params
private helper method and use it to grab the params we want. We then use it in the calls to our Post
model in the create
and update
actions.
The params.require(:post)
call makes sure that there is something at params[:post]
. Subsequently, .permit(...)
grabs the pairs out of that params[:post]
hash that we want and allows them to be passed to Post
.
A similar params
method will be needed in the comments controller. Be sure to add that in as well so that your app works as intended. Additionally, you will need to change your create action for comments_controller.rb
def create
@comment = @post.comments.build(comment_params)
if @comment.save
# ...
else
@post.reload.comments
# ...
end
end
When comment validation fails, even though the comment is not saved in the database, it is still being associated with the current post in memory. This will raise an exception when rendering the show.html.erb
because of its dependency on comment.id
where our invalid comment will have an id of nil
. Because of the way we wrote our code, we are grabbing all the comments associated with the current post in memory rather than directly from the database. To solve this, we need to add @post.reload.comments
during comment validation failures to make sure our current post is synced with the database.
For more on these topics, check out: