19

Models: Posts and Users

Post belongs_to :user
User has_many :posts

Simple.

Assuming a few users exist, we visit the edit page for a Post.

<%= form_for @post do |f| %>

...

<% User.all.each do |user| %>
  <div><%= f.radio_button "user_id", user.id %></div>
<% end %>

...

The Post's Controller leverages Rails 4 strong parameters.

params.require(:post).permit(:user_id)

Assume the edit post form only has the radio buttons as fields.

Problem: ActionController::ParameterMissing exception is thrown. param not found: post

The reason being the Post params hash is never created, causing the above exception to be thrown. Empty radio buttons, unlike empty text fields for example, do not trigger the model's param hash to be created.

What if the Post model requires a user_id to be valid? Certainly one would want to render the view again with the reason why the Post can't be saved.

Question: What is an elegant way to handle this situation while sticking to Rails convention?

UPDATE:

Brainstorming about this further, I'm sure there are probably plenty of other situations which generate this problem; it does not necessarily correspond to radio buttons.

Benjamin
  • 1,832
  • 1
  • 17
  • 27
  • I have an even weirder issue... I get the same param not found for the model hash but what I'm testing is a form_for @user with two of user's fields and that is it. my url happens to use username and i would think it was missing id or something. but i have another part of my project which does the same thing. the only difference is i built this form from scratch rather than through scaffold... – dtc Feb 22 '14 at 07:21

2 Answers2

32

I have a similar problem, and didn't like either of these answers much. In the rails documentation (http://guides.rubyonrails.org/action_controller_overview.html#more-examples) I see the following solution:

params.fetch(:blog, {}).permit(:title, :author)

Effectively you are supplying a default of {}, which seems to work well enough (at least for my situation).

Applying to your code, you'd have:

params.fetch(:post, {}).permit(:user_id)

I think this is reasonably clean, and seems to work in my code.

PaulL
  • 6,650
  • 3
  • 35
  • 39
  • 1
    Awesome! This was the solution I was looking for all along. – Benjamin Mar 17 '14 at 23:30
  • Thank you PaulL. You saved my life. I also tried using Ben's solution but it gives me this error: When assigning attributes, you must pass a hash as an argument. – cyonder Oct 14 '15 at 21:19
4

This was my immediate solution... though it seems a bit silly because why are you having to check for the post params if you are clearly in the post controller and you require them anyways. Seems very counterintuitive. Is this really the best way?

  params.require(:post).permit(:user_id) if params[:post]
Benjamin
  • 1,832
  • 1
  • 17
  • 27
  • 2
    @ConnorLeech it works because the original problem was params[:post] doesn't get created, and the if simply checks for that before running the strong params methods. If the params don't exist at all, the method simply returns nil. Nil works in most, if not all model update methods, so everything works out. I don't like it much because an exception is SUPPOSED to be thrown if the post params don't exist (one of the whole points of strong parameters). Nothing happening at all is not what I would consider the expected behavior. – Benjamin Nov 30 '13 at 00:52
  • It will need to check the params[:post] also in controller to further proceed to value params[:post][:user_id] – V-SHY Jan 17 '16 at 15:23