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="f.label" hotel="hotel" id="id" _="_">: <_ f.text_field="f.text_field" _:hotel_id="_:hotel_id" _="_">

<_ f.label="f.label" name="name" _="_">: <_ f.text_field="f.text_field" _:name="_:name" _="_">

<_ f.label="f.label" destination="destination" id="id" _="_">: <_ f.text_field="f.text_field" _:destination_id="_:destination_id" _="_">

> >

<_ f.submit="f.submit" save="save" _="_">

<_ end="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

(…)

Posted: 28 May 2009

comments powered by Disqus