NoBrainer::Error::DocumentNotPersisted - Duplicate primary key #139

Closed
MadBomber opened this Issue May 1, 2015 · 7 comments

Comments

Projects
None yet
3 participants
@MadBomber

NoBrainer::Error::DocumentNotPersisted - Duplicate primary key

Maybe I'm using the wrong pattern. Within a Sinatra app I call my method get_account(params) which returns an Account record from the RethinkDB database. If there was no record matching the what I wanted a new is created which means that that get_account(params) always returns an Account model.

I change a few fields and do account.save expecting the record to be updated. Instead I get the error about duplicate primary key. If I do account.update instead I get an error saying that I did not have the proper number of arguments to the update method.

So it looks like I have to provide a Hash to the update method for thise fields I want changed. This feels odd. I hope I am wrong.

Dewayne
o-*

@nviennot

This comment has been minimized.

Show comment
Hide comment
@nviennot

nviennot May 2, 2015

Owner

Can you provide a little code example that would trigger the bug?
That would be very helpful

Owner

nviennot commented May 2, 2015

Can you provide a little code example that would trigger the bug?
That would be very helpful

@MadBomber

This comment has been minimized.

Show comment
Hide comment
@MadBomber

MadBomber May 2, 2015

I am using rethinkdb with a sinatra app. The Account model is basically a User model with lots of user oriented fields. The one odd field is the phones Array field that is indexed with :multi => true.

This is the pattern that I am using:

class Account
  include NoBrainer::Document
  include NoBrainer::Document::Timestamps
  field :phones, :type => Array, :default => []
  index :phones, :multi => true
end

# if account does not exist for this phone number then
# create a guest account
def get_account(params)
  account = Account.where(:phones.any => params['Caller']).limit(1).run
  account = account.first if Array == account.class
  if account.nil?
    account = create_a_new_account(params)
    logger.info "New guest account created for #{params['Caller']}"
  else
    account = Account.new(account)  # SMELL: Turn Hash into an Account object
  end
  return account
end

def create_a_new_account(params)
  account = Account.new
  account.phones << params['Caller']
  account.save!
  return account
end

# http://localhost:4567/test?Caller=+16155551212
get '/test' do
  account = get_account params
  # make changes to some of the model's attributes
  account.save # raises duplicate primary key
end

One of the things I'm having trouble grappling with is that the ORM model is not always the returned object. The version of NoBrainer that I am using is: 0.23.0

I am getting the same exception regardless of wither I am running the sinatra app or running the model and support methods within irb.

I am using rethinkdb with a sinatra app. The Account model is basically a User model with lots of user oriented fields. The one odd field is the phones Array field that is indexed with :multi => true.

This is the pattern that I am using:

class Account
  include NoBrainer::Document
  include NoBrainer::Document::Timestamps
  field :phones, :type => Array, :default => []
  index :phones, :multi => true
end

# if account does not exist for this phone number then
# create a guest account
def get_account(params)
  account = Account.where(:phones.any => params['Caller']).limit(1).run
  account = account.first if Array == account.class
  if account.nil?
    account = create_a_new_account(params)
    logger.info "New guest account created for #{params['Caller']}"
  else
    account = Account.new(account)  # SMELL: Turn Hash into an Account object
  end
  return account
end

def create_a_new_account(params)
  account = Account.new
  account.phones << params['Caller']
  account.save!
  return account
end

# http://localhost:4567/test?Caller=+16155551212
get '/test' do
  account = get_account params
  # make changes to some of the model's attributes
  account.save # raises duplicate primary key
end

One of the things I'm having trouble grappling with is that the ORM model is not always the returned object. The version of NoBrainer that I am using is: 0.23.0

I am getting the same exception regardless of wither I am running the sinatra app or running the model and support methods within irb.

@ajselvig

This comment has been minimized.

Show comment
Hide comment
@ajselvig

ajselvig May 2, 2015

Contributor

account = Account.new(account)

This is unnecessary (wrong), since account is the result of a where
query, so it's already a NoBrainer object. Based on your code, it should
never be a hash, so I'm a bit confused by the SMELL comment.

Also, the top two lines of get_account can be replaced with:

account = Account.where(:phones.any => params['Caller']).first

Contributor

ajselvig commented May 2, 2015

account = Account.new(account)

This is unnecessary (wrong), since account is the result of a where
query, so it's already a NoBrainer object. Based on your code, it should
never be a hash, so I'm a bit confused by the SMELL comment.

Also, the top two lines of get_account can be replaced with:

account = Account.where(:phones.any => params['Caller']).first

@MadBomber

This comment has been minimized.

Show comment
Hide comment
@MadBomber

MadBomber May 2, 2015

On Friday, May 01, 2015 09:18:09 PM Andy Selvig wrote:

account = Account.where(:phones.any => params['Caller']).first

That gets nomethod exceptions because the result of the where method is a
NoBrainer::Criteria

I am working this weekend on getting everything down to a simple test case.
Prehaps in the process I will find a light bulb.

Dewayne
o-*

On Friday, May 01, 2015 09:18:09 PM Andy Selvig wrote:

account = Account.where(:phones.any => params['Caller']).first

That gets nomethod exceptions because the result of the where method is a
NoBrainer::Criteria

I am working this weekend on getting everything down to a simple test case.
Prehaps in the process I will find a light bulb.

Dewayne
o-*

@nviennot

This comment has been minimized.

Show comment
Hide comment
@nviennot

nviennot May 2, 2015

Owner

Try this:

class Account
  include NoBrainer::Document
  include NoBrainer::Document::Timestamps

  field :phones, :type => Array, :default => [], :index => :multi
end

# if account does not exist for this phone number then
# create a guest account
def get_or_create_account(params)
  account = Account.where(:phones.any => params['Caller']).first
  if account.nil?
    account = create_a_new_account(params)
    logger.info "New guest account created for #{params['Caller']}"
  end
  return account
end

def create_a_new_account(params)
  account = Account.new
  account.phones << params['Caller']
  account.save!
  return account
end

# http://localhost:4567/test?Caller=+16155551212
get '/test' do
  account = get_or_create_account params
end

Basically, you need to use .first instead of limit(1).run like @ajselvig said.

(http://nobrainer.io/docs/querying/#first_first_last_last_sample)

Owner

nviennot commented May 2, 2015

Try this:

class Account
  include NoBrainer::Document
  include NoBrainer::Document::Timestamps

  field :phones, :type => Array, :default => [], :index => :multi
end

# if account does not exist for this phone number then
# create a guest account
def get_or_create_account(params)
  account = Account.where(:phones.any => params['Caller']).first
  if account.nil?
    account = create_a_new_account(params)
    logger.info "New guest account created for #{params['Caller']}"
  end
  return account
end

def create_a_new_account(params)
  account = Account.new
  account.phones << params['Caller']
  account.save!
  return account
end

# http://localhost:4567/test?Caller=+16155551212
get '/test' do
  account = get_or_create_account params
end

Basically, you need to use .first instead of limit(1).run like @ajselvig said.

(http://nobrainer.io/docs/querying/#first_first_last_last_sample)

nviennot added a commit that referenced this issue May 2, 2015

@MadBomber

This comment has been minimized.

Show comment
Hide comment
@MadBomber

MadBomber May 6, 2015

please pardon the delay. I think the key item was to

Basically, you need to use .first instead of limit(1).run like @ajselvig said.

I remove as much of the ReQL from my app - sticking NoBrainer. That cleared up lots of little problems.

please pardon the delay. I think the key item was to

Basically, you need to use .first instead of limit(1).run like @ajselvig said.

I remove as much of the ReQL from my app - sticking NoBrainer. That cleared up lots of little problems.

@MadBomber MadBomber closed this May 6, 2015

@nviennot

This comment has been minimized.

Show comment
Hide comment
@nviennot

nviennot May 6, 2015

Owner

Cool :)

Owner

nviennot commented May 6, 2015

Cool :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment