Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialchris salvi
7,584 PointsUpgrade to rails 4.x for treebook went flawless until I hit one minor snag
When I login and try to post a new status, I get the error message screen telling me the following:
ActiveModel::ForbiddenAttributesError
Now I assume this must be something new to 4.0 as I followed the video carefully and double checked my create method in my status_controller. I will post a screenshot for assurance.
Anyone know what I need to do here so I can create posts again in the upgrade app?
3 Answers
Matt West
14,545 PointsYep, you will need to alter the update line as you're doing mass assignment here (altering multiple attributes by passing an object).
@status.update(status_params)
That set_status
method is a nice design pattern to use.
Make sure you have a before_filter
set up that calls the method before the update
action.
You then can remove the first line of your update
action.
One note here is that you will need to change the code in your set_status
method to make sure that nobody can alter other people's statuses. Just use the first line of your current update
action instead.
# TODO: Add more actions in the array here.
# Anywhere that you need to get the status by ID (i.e. `edit`).
before_filter :set_status, only: [:update]
private
def set_status
@status = current_user.statuses.find(params[:id])
end
You can also delete the following if you make sure that user_id
is not listed in your permitted parameters.
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
Matt West
14,545 PointsHi Chris,
Rails 4 introduces some changes to how parameters are handled in controllers, specifically when it comes to mass assignments like you're doing here in your create
action.
Whereas before attributes were secured in the model using attr_accessible
, rails 4 now secures parameters in the controller.
This new feature is called strong parameters. You can read about it here: http://guides.rubyonrails.org/v4.0.8/action_controller_overview.html#strong-parameters
You now need to whitelist parameters used in mass assignments before they can be used in your controller. This change helps to prevent unwanted parameters from making their way into your database queries, making your rails app more secure.
There's two key changes you'll need to make to your code.
First, create a private status_params
method that defines the permitted parameters. See the code below for an example.
Make sure you update the parameters listed in the permit
method to match the attributes of the Status model you need to change.
Second you need to update your create
action to use status_params
instead of params[:status]
when creating the new status.
Here's a modified example of your code. I don't have the treebook project to hand, so apologies if any of this is off. It should however give you an idea of where you need to make changes.
class StatusController < ActionController::Base
def create
# You now use status_params instead of params[:status]
@status = current_user.statuses.new(status_params)
# The rest of your code in the create action is just fine :)
end
# More controller actions in here...
private
def status_params
# TODO: Change the parameters listed within `permit` to match the Status attributes you need to change.
params.require(:status).permit(:name, :age)
end
end
Post your full status_controller.rb
file if you encounter any issues and I'll do my best to help out :)
chris salvi
7,584 Pointsyou are my ruby savior, Matt. I have had some difficulty with the new strong params requirement in 4.0, but I think Im finally getting a better grasp on it with that link above. Thanks!
Matt West
14,545 PointsGood to hear!
Strong params threw me out a bit at first too. It makes total sense once you get used to it though :)
chris salvi
7,584 PointsOne last question Matt West
Here is my update status: http://postimg.org/image/w9v7p0txp/
do I need to change the instance @status here as well, and do I need to alter the conditional statement below it as well?
chris salvi
7,584 PointsI have this method along with status_params under private methods
def set_status @status = Status.find(params[:id]) end
chris salvi
7,584 Pointsclass StatusesController < ApplicationController
before_action :set_status, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, only: [:new, :create, :edit, :update]
# GET /statuses
# GET /statuses.json
def index
@statuses = Status.all
end
# GET /statuses/1
# GET /statuses/1.json
def show
end
# GET /statuses/new
def new
@status = Status.new
end
# GET /statuses/1/edit
def edit
end
# POST /statuses
# POST /statuses.json
def create
@status = current_user.statuses.new(status_params)
respond_to do |format|
if @status.save
format.html { redirect_to @status, notice: 'Status was successfully created.' }
format.json { render :show, status: :created, location: @status }
else
format.html { render :new }
format.json { render json: @status.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /statuses/1
# PATCH/PUT /statuses/1.json
def update
@status.update(status_params)
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
respond_to do |format|
if @status.update(params[:status])
format.html { redirect_to @status, notice: 'Status was successfully updated.' }
format.json { render :show, status: :ok, location: @status }
else
format.html { render :edit }
format.json { render json: @status.errors, status: :unprocessable_entity }
end
end
end
# DELETE /statuses/1
# DELETE /statuses/1.json
def destroy
@status.destroy
respond_to do |format|
format.html { redirect_to statuses_url, notice: 'Status was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_status
@status = current_user.statuses.find(params[:id])
end
def status_params
params.require(:status).permit(:user_id, :content)
end
end
chris salvi
7,584 Pointschris salvi
7,584 PointsMatt West
Hey mate, running into issues again. When I try to post a new status I now receive this error. Boy this is rough.... Thanks for all your help
http://postimg.org/image/odewt8jn9/
Matt West
14,545 PointsMatt West
14,545 PointsHey Chris,
What does your
Status
model look like? Please post the code and I'll take a look.chris salvi
7,584 Pointschris salvi
7,584 PointsMatt West
14,545 PointsMatt West
14,545 PointsSorry, I meant the
status.rb
file in theapp/models
folder.Do you have your code hosted on GitHub? That might be easier than having to copy and paster everything :)
chris salvi
7,584 Pointschris salvi
7,584 PointsI do. Here you go
https://github.com/donsalvadori
Matt West
14,545 PointsMatt West
14,545 PointsThanks Chris,
Try the following:
full_name
is a method on theUser
model so you'll need to call it on the owner of the status, not the status itself. (i.e.@status.user
)chris salvi
7,584 Pointschris salvi
7,584 PointsSorry, that is what I originally had before messing around with it, but it still throws the same error message that I listed before :(
Matt West
14,545 PointsMatt West
14,545 PointsThat's strange, I just cloned the repo to my computer and made the change. It fixed the error.
I've submitted a pull request on Github. Merge it into your repo and give it a go.
chris salvi
7,584 Pointschris salvi
7,584 Pointsok will do when I get home from work. Thanks for helping me out btw. You are very kind and part of what makes this community great!
Matt West
14,545 PointsMatt West
14,545 PointsNo problem :)
chris salvi
7,584 Pointschris salvi
7,584 PointsThanks matt, youre the best.
One last question, I have tried to mess around with the CSS to make my links at the top of the page on the nav bar inline, but havent been able to do so yet. In theory this should be easy, but Im guessing it's because Im using a more modern version of bootstrap than the videos. Do you see any suggestions I can make to fix this?
Obrigado!
Matt West
14,545 PointsMatt West
14,545 PointsHi Chris,
I've made some alterations to my fork on Github that I think will get things looking how you'd like. Take a look at the updated
application.html.erb
file: https://github.com/matt-west/treebook/blob/master/app/views/layouts/application.html.erbAnd the update
application.css
: https://github.com/matt-west/treebook/blob/master/app/assets/stylesheets/application.cssLet me know if you have any queries about the alterations.