Dirk Bergmann

Developer, panographer. Does consultancy work from own company. Lives in Chiang Mai, Thailand.

Twitter

Chiang Mai

Hua Hin

Thailand Hotels

ListVote - List. Vote. Learn.

Partnerseek - Find Partners

Custom Primary Key and Mass Assignment

Say you have an ActiveRecord model with a custom primary key and no field named “id”, a common occurrence when working with legacy data:

hotel.rb

class Hotel < ActiveRecord::Base
  set_primary_key :hotel_id

 (…)

Now you have the pertinent form

<% form_for(@hotel) do |f| %>
  <%= f.error_messages %>
 


    <%= f.label 'Hotel ID' %>:
    <%= f.text_field :hotel_id %>
 


 


    <%= f.label 'Name' %>:
    <%= f.text_field :name %>
 



    <%= f.label 'Destination ID' %>:
    <%= f.text_field :destination_id %>
 

 


    <%= f.submit 'Save' %>
 


<% end %>

and default controller code:

hotels_controller.rb 

def create
    @hotel = Hotel.new(params[:hotel])

    respond_to do |format|

if @hotel.save

(…)

However, this won’t work. The mass assignment at

@hotel = Hotel.new(params[:hotel])

can’t be used with a “custom” primary key as this code called by the initializer excludes the primary key:

active_record/base.rb

def attributes_from_column_definition
        self.class.columns.inject({}) do |attributes, column|
          attributes[column.name] = column.default **unless column.name == self.class.primary_key
**          attributes
        end
      end

It is therefore necessary to call the initializer (Hotel.new) without the params hash and set the attributes manually:

hotel_controller.rb 

def create
    @hotel = Hotel.new
    my_params = params[:hotel]
    @hotel.hotel_id = my_params[:hotel_id]
    @hotel.name_english = my_params[:name]
    @hotel.destination_id = my_params[:destination_id]

 respond_to do |format|
      if @hotel.save

(…)