Just getting started with Rails 4.1, and I'm having a hard time understanding something that's going on when I try to update a model using the update_attributes method. I've written a small app to learn on that lets users review beers. A user can edit their reviews using a form that looks like this:
<%= form_for review do |f| %>
<%= f.label :rating %>
<%= f.select :rating, 1..5%>
<%= f.label :review_text %>
<%= f.text_area :review_text %>
<%= hidden_field_tag :beer_id, @beer.id %>
<%= hidden_field_tag :on_wishlist, "f" %>
<%= f.submit %>
<% end %>
The controller has a simple update action that looks like this:
@review.update_attributes(review_params)
And the parameters look like this:
def review_params
params.require(:review).permit(:rating, :user_id, :beer_id, :review_text, :on_wishlist)
end
All pretty simple. What I can't figure out is why this only works to update some of the attributes. In particular, the on_wishlist attribute does not get updated. If I look in the server log I see the following:
Parameters: { ... "review"=>{"rating"=>"5", "review_text"=>"What a good beer"}, "beer_id"=>"4", "on_wishlist"=>"f", "commit"=>"Update Review", "id"=>"7"}
...
SQL (0.5ms) UPDATE "reviews" SET "rating" = ?, "review_text" = ?, "updated_at" = ? WHERE "reviews"."id" = 7 [["rating", 5], ["review_text", "What a good beer"], ["updated_at", "2015-01-15 22:51:56.009256"]]
So I can see that the on_wishlist hidden field is being sent to the server, just not included in the update, even though it's in the review_params hash.
If I change the controller code to the following, it works fine:
@review.update_attributes(review_params)
@review.on_wishlist = params[:on_wishlist]
@review.save
But I don't understand why on_wishlist should have to be treated separately. The only relevant detail I can think of is that on_wishlist was added in a separate migration from the rest of the review, as follows:
class AddOnWishlistToReviews < ActiveRecord::Migration
def change
add_column :reviews, :on_wishlist, :bool, :default => false
end
end
I'm sure I'm missing something simple--thanks for your help.
It's because you defined beer_id
and on_wishlist
as separate fields in form. Other fields you defined with object form f
.
You can see in params was sent to server, you only have:
"review"=>{"rating"=>"5", "review_text"=>"What a good beer"}
So, your object @review
can only update these field. The review_params
actually is params[:review]
.
So if you want to update beer_id
and on_wishlist
, you can make these fields belongs to object in form by using f
object:
<%= f.hidden_field :beer_id, value: @beer.id %>
<%= f.hidden_field :on_wishlist, value: "f" %>
or change name of them:
<%= hidden_field_tag :beer_id, @beer.id, name: 'review[beer_id]' %>
<%= hidden_field_tag :on_wishlist, "f", name: 'review[on_wishlist]' %>