2

I'm working on a small demo app to help myself understand how to implement cascading selects on Rails 4, but I've run into an interesting problem:

When I fill out a form and submit it to the database, the parameters seem to be passed, but the values are not being saved in the database because the SQL skips the field names and values, as demonstrated in this snippet from the console:

Started POST "/prop_sub_types" for ::1 at 2015-01-23 18:54:05 -0800
Processing by PropSubTypesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"7mGqF/MR+IKrKKdAKBYBI/E7pl7PCJasHDLN5T1/ohF/qEuXyhwsm8d87xDvfmcxk590hp/2XuenQBDaGhI+IA==", "prop_sub_type"=>{"name"=>"sub foo", "prop_type_id"=>"1"}, "commit"=>"Create Prop sub type"}
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "prop_sub_types" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2015-01-24 02:54:05.218673"], ["updated_at", "2015-01-24 02:54:05.218673"]]
   (2.2ms)  commit transaction
Redirected to http://localhost:3000/prop_sub_types/1
Completed 302 Found in 7ms (ActiveRecord: 2.6ms)

This is the relevant bit of schema.rb that demonstrates that the columns are there:

  create_table "prop_sub_types", force: :cascade do |t|
    t.string   "name"
    t.integer  "prop_type_id"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
  end

Model:

class PropSubType < ActiveRecord::Base
  attr_accessor :name, :prop_type_id

  belongs_to :prop_type
  has_many :appraisals
end

Controller (relevant portions for the sake of brevity -- I can post more if needed):

def create
    @prop_sub_type = PropSubType.new(prop_sub_type_params)

    respond_to do |format|
      if @prop_sub_type.save
        format.html { redirect_to @prop_sub_type, notice: 'Prop sub type was successfully created.' }
        format.json { render :show, status: :created, location: @prop_sub_type }
      else
        format.html { render :new }
        format.json { render json: @prop_sub_type.errors, status: :unprocessable_entity }
      end
    end
  end

...

private
    # Use callbacks to share common setup or constraints between actions.
    def set_prop_sub_type
      @prop_sub_type = PropSubType.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def prop_sub_type_params
      params.require(:prop_sub_type).permit(:name, :prop_type_id)
    end

app/views/prop_sub_types/_form.html.erb:

<%= form_for(@prop_sub_type) do |f| %>
  <% if @prop_sub_type.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@prop_sub_type.errors.count, "error") %> prohibited this prop_sub_type from being saved:</h2>

      <ul>
      <% @prop_sub_type.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :prop_type_id %><br>
    <%= f.number_field :prop_type_id %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

I'm adapting some Rails 3 code, so I thought I messed up the strong parameters portion, but the code actually looks correct to me and compares well with an unrelated, but working Rails 4 application.

What did I do wrong to make the INSERT ignore my parameters?

MarsAtomic
  • 10,436
  • 5
  • 35
  • 56

1 Answers1

4

I believe it is because of your attr_accessor :name, :prop_type_id in model. Those accessors definitely are redundant and override the right ones: all fields for the DB table's fields are created as a part of initializing AR:Base class

Roaring Stones
  • 1,054
  • 7
  • 22
  • OP is likely confusing `attr_accessor` with the old `attr_accessible` – numbers1311407 Jan 24 '15 at 03:40
  • @numbers1311407 exactly – Roaring Stones Jan 24 '15 at 03:42
  • 1
    @RoaringStones Oh... holy monkeys! ActiveRecord includes getters and setters transparently? I was comparing this failing app with a working app where I actually include attr_accessor not only for a couple of virtual attributes, but for each and every field (real db fields), yet it works. I'd love to know why this is the case, but perhaps that's a separate question. – MarsAtomic Jan 24 '15 at 03:50
  • @MarsAtomic yeah... if it was kind of tricky question I am asked on some tech interview I would think that attr_accessor won't affect the work much: at all of the ends I believe Rails make those just as instance variables. But in Rails 4 I think those are more than that. If you find the real answer, begging you, post a link here and notice me :) – Roaring Stones Jan 24 '15 at 04:00
  • @RoaringStones Now that I know where my problem was, I have a clear target. See this [question](http://stackoverflow.com/questions/14401768/how-does-activerecord-define-methods-compared-to-attr-accessor/14452353#14452353) for a start. I'll see what else I can find later on as I study more about ActiveRecord. – MarsAtomic Jan 24 '15 at 04:07
  • @RoaringStones Just to close this issue out finally: listing a field under attr_accessor that is part of the record will *always* cause that field to be overridden. When I was double checking my code, I wasn't careful enough to notice that some of the virtual attributes listed under attr_accessor were named similarly to, but not identically to, fields within the record. – MarsAtomic Jan 27 '15 at 20:47