Search code examples
ruby-on-railsruby-on-rails-4activerecordmodelupdate-attributes

Some attributes of Rails model not being updated by update_attributes method


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.


Solution

  • 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]' %>