markstewie
markstewie

Reputation: 9587

Rails belongs_to and has_many relationships problems

I'm pretty new to rails, building my first 'real' app and struggling to understand how to make relationships work properly.

I have a Quiz model and and Icon model. Each Quiz belongs_to an Icon, an Icon has_many Quizzes. (think of an icon as a category).

On my "new/edit" Quiz forms I want a select box to choose the correct Icon. At the moment I have...

<%= collection_select(:quiz, :icon_id, Icon.all, :id, :title, :prompt => true) %>

And in my Quiz controller create action I have...

def create
   @icon = Icon.find(params[:quiz][:icon_id])
   @quiz = @icon.quizzes.build(params[:quiz])
   if @quiz.save
     flash[:success] = "New quiz created successfully!"
     redirect_to @quiz
   else
     render 'new'
   end
end

When I submit the form I get a

Can't mass-assign protected attributes: icon_id

error which I understand as icon_id isn't assigned as being attr_accessible in the model.

I could either make it accessible as there is no real security risk around this or I could remove the icon_id from the quiz hash before passing to the build method but both these options don't seem like the right way to do things.

What is the right way to do this?

Thanks!

Upvotes: 0

Views: 118

Answers (2)

Doug R
Doug R

Reputation: 5779

TL;DR: Rails has a feature called mass assignment, which is what you are doing when you pass in that params[:quiz] hash. You need to specify attr_accessible for any attributes you wish to update using mass assignment.

A quick history lesson:

It used to be that all attributes were mass assignable by default, so your code would have worked just fine.

A number of months ago, there was a highly publicized episode at github where somebody was able to exploit this feature by constructing a post body with something to the effect of user[:admin] = true. This effectively gave the user admin access, because the application didn't prevent just anybody from setting admin = true. There was a way to prevent this, but the developers missed it.

The response by Rails to this was to make all attributes protected by default, forcing the developer to explicitly specify any fields available to be updated via mass assignment. I believe this was in the 3.2.3 release.

Upvotes: 2

damuz91
damuz91

Reputation: 1748

Just put

attr_accessible :icon_id

in your Quiz model.

From the Ruby on rails api: attr_accessible: Specifies a white list of model attributes that can be set via mass-assignment.

Upvotes: 2

Related Questions