Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postgres Table Inheritance Support #4313

Closed
robertsosinski opened this issue Jan 5, 2012 · 5 comments
Closed

Postgres Table Inheritance Support #4313

robertsosinski opened this issue Jan 5, 2012 · 5 comments

Comments

@robertsosinski
Copy link

Hello,

It seems certain operations (finding by id, inserting, updating) has issues when using table inheritance. For example, I have the following three tables:

create table trades (
  id serial primary key,
  price money,
  quantity integer,
  created_at timestamp,
  updated_at timestamp
);

create table stock_trades (
  ticker varchar
) inherits(trades);

create table bond_trades (
  cusip varchar
) inherits(trades);

All operations work correctly on the trades table, but for the stock_trades and bond_trades table, things get a bit finicky with the id field. I can do StockTrade.where(:id => 1), or StockTrade.find_by_id(1). However, if I do StockTrade.find(1), the query fails with the following:

ERROR:  zero-length delimited identifier at or near """" at character 68
STATEMENT:  SELECT  "stock_trades".* FROM "stock_trades"  WHERE "stock_trades"."" = $1 LIMIT 1

You'll notice that it is not referencing the id in the where clause (being just an empty set of quotes).

Creating new records on stock_trades or bond_trades also yields a problem with the id. Creating a new stock trade with StockTrade.create(:price => '33.33'.to_d, :quantity => 100, :ticker => 'VZ') for example, fails with the following:

ERROR:  null value in column "id" violates not-null constraint
INSERT INTO "stock_trades" ("created_at", "id", "price", "quantity", "ticker", "updated_at") VALUES ($1, $2, $3, $4, $5, $6);

The issue seems to be that Postgres trying to write to the id with a null, instead of leaving it out of the values list.

Updating also has problems as well. Doing st = StockTrade.find_by_id(1); st.update_attribute(:quantity, 101) fails with the following:

ERROR:  zero-length delimited identifier at or near """" at character 110
STATEMENT:  UPDATE "stock_trades" SET "quantity" = 101, "updated_at" = '2012-01-05 04:45:55.734441' WHERE "stock_trades"."" = 1

Overall, it seems that ActiveRecord is not seeing the id column, or is not identifying it as an id.

@pixeltrix
Copy link
Contributor

The problem is in the pk_and_sequence_for method in PostgreSQLAdapter - the query doesn't find anything for the stock_trades table. The query could probably adapted to work with table inheritance, however I'd caution against using it because you're likely to come up against other problems, especially when loading/dumping schemas, migrations, etc.

@robertsosinski
Copy link
Author

Hey Pixeltrix

Been playing around with this again and noticed that adding self.columns_hash['id'].primary = true to an ActiveRecord model fixes the issue I am having with the primary key. As such, my models look as follows:

# trade.rb
class Trade < ActiveRecord::Base
  self.abstract_class = true

  def expensive?
    self.price > 100
  end

  def alot?
    self.quantity > 100
  end
end

# stock_trade.rb
class StockTrade < Trade
  self.columns_hash['id'].primary = true
end

# bond_trade.rb
class BondTrade < Trade
  self.columns_hash['id'].primary = true
end

Do you see any problems with doing this, or if support for this will ever be rolled into Rails proper?

@drogus
Copy link
Member

drogus commented May 20, 2012

I've checked it on both master and 3-2-stable and it works correctly. @robertsosinski let me know if this is still an issue for you.

@drogus drogus closed this as completed May 20, 2012
@joemsak
Copy link

joemsak commented Apr 24, 2013

Just to add for posterity, I had this same issue when using "acts_as_nested_set" and MY fix was not to put in the self.columns_hash ['id'] line, but to do this in my parent class:

parent

#...
self.abstract_class = true

def self.inherited(base)
  base.acts_as_nested_set
end

#...

child

class ChildThing < ParentThing
end

worked fine for me!

@jeremywadsack
Copy link
Contributor

Unfortunately, neither of these solutions worked for me on a Rails 3.2.17. For my needs I ended up sorting the array in memory after pulling from the DB.

pk_and_sequence_for doesn't exists in master so pixeltrix's link is no longer valid, but here's the 3.2-stable function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants