Forum: Ruby on Rails can't create record with id

Posted by Nishan T. (nishan_t)
on 2013-01-31 17:01
I'm migrating the tables with existing data
I've users table and all other tables contains the user_id column and
now i need seperate the users into two (users & customers) tables
So i need to migrate the new customers table with existing users records
where the user type with customer

I need to create a customers table and set the id of users records with
user type as customer,
which will be easy instead of migrating many of other tables(which is
used only by customers) by checking every record with user's user type
and assign the new id of customers table.

My tables should looks like

users table:

    id  |    name   |   ...
   ------------------------------
    1  |    aaa    |  ...
    2  |    bbb    |  ...
    4  |    ddd    |  ...
    6  |    fff    |  ...

customers table

    id   |    name  |  ...
   -------------------------------
    3  |    ccc      |  ...
    5  |    eee      |  ...
    7  |    ggg      |  ...

When i'm migrating users existing data, I can't assign the id of user as
customer's primary id

In my migration file

  def up
    create_table(:customers) do |t|
      t.string :name
    end

    User.joins(:user_type).where(:user_type => {:type_name =>
'customer'}).find_in_batches(:batch_size => 100){ |users|
       users.each {|user|
              customer = Customer.new
              customer.id = user.id
              customer.name = user.name
              customer.save(:validate => false)
       }
       }
  end

Also tried

  Customer.create!(:id => user.id) instead of save method

And

  INSERT INTO customers(id, name) VALUES("#{user.id}", "#{user.name}")

Finally all ended with same error

Error: Called id for nil, which would mistakenly be 4 -- if you really
wanted
the id of nil, use object_id

Is this correct?

Is there any way to assign the primary id ?

Please anyone explain how to do this?
Posted by Colin Law (Guest)
on 2013-01-31 18:06
(Received via mailing list)
On 31 January 2013 16:01, Nishan T. <lists@ruby-forum.com> wrote:
> I'm migrating the tables with existing data
> I've users table and all other tables contains the user_id column and
> now i need seperate the users into two (users & customers) tables
> So i need to migrate the new customers table with existing users records
> where the user type with customer

Are you sure you want to do it that way?  It may well be simpler to
keep one table with flags to indicate the type of the user.
Alternatively you could use STI (though again this may be more complex
than just flags).  Also there is the cancan gem that allows users to
have various roles (user and customer in this case).  Remember that
you can have multiple relationships between the same tables with
different association names for the different cases.  Also remember
that you can have self-referential associations so that if you want
relationships between users and customers that can still be done even
if they are in the same table.  See the Rails Guide on ActiveRecord
Associations.

If you can't see how this would work post the proposed relationships
between users, customers and the rest for suggestions on how to
achieve the same thing with a single table.

Colin
Posted by Rob Biedenharn (Guest)
on 2013-01-31 22:34
(Received via mailing list)
tl;dr Yes, you /can/ even if Colin's advice is good (AND I agree with 
him!)
customer = Customer.new(other_attributes_here) {|c| c.id = user.id }
customer.save

On Jan 31, 2013, at 11:01 AM, Nishan T. wrote:

> and assign the new id of customers table.
>    6  |    fff    |  ...
> customer's primary id
Well, what you can't do is use "mass assigment" to set the id of an 
ActiveRecord model.

You can, however, set the id on a new record and it will be honored if 
the database doesn't forbid it. (For example, if that primary key value 
already existed.)

>       users.each {|user|
>  Customer.create!(:id => user.id) instead of save method
>
> Is this correct?
>
> Is there any way to assign the primary id ?
>
> Please anyone explain how to do this?

There's even a block form of ActiveRecord.new that passes in the newly 
initialized object.

customer = Customer.new(:name => user.name) {|c| c.id = user.id }
customer.save(:validate => false)

Since you already have a "user_type", it seems like you're at least 
halfway to being STI (Single-Table Inheritance) anyway.

Couldn't you have:

class Customer < User
end

Then you'd have a `type` attribute (column) in the users table which 
would hold the class name represented by that row of data. (which could 
be "User" or could be "Customer")

Then you can say:
  r = User.find_by_name('ccc')
and r will hold an instance of the Customer class.

-Rob
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.