Forum: Ruby on Rails 2 Rails Quirks

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-07-25 17:23
(Received via mailing list)
I have two problems with my Rails code that seem like they should be
easy fixes but I can't figure it out. Anyone looking at the code below
will probably think it looks weird or redundant but it's the only way
I've gotten it to work. I'd rather do it right though. The first
problem is that I have to define the ID outside of the call to new. If
I define the ID in new, it never gets defined for whatever reason and
I get a not null constraint violation on productid. Why is it that I
have to define it outside of new to make it work? The second problem
is the call to save. My understanding of save is that it creates a new
record if no matching record exists, otherwise it updates the matching
record. Well, for some reason I keep getting:

Exception encountered: RuntimeError: ERROR      C23505  Mduplicate key
violates unique constraint supplier_stock_pkey" Fnbtinsert.c
L255    R_bt_check_unique: INSERT INTO supplier_stock ("productid",
yesterday_stock", "current_stock") VALUES(525542, 0, -1)

Why is it not updating instead of trying to create a new record?
Thanks.

Working code:

    begin
      product = SupplierStock.new(
        :current_stock => s
      )
      product[:productid] = prodid
      product.save
      end
    rescue Exception => e
      SupplierStock.update(
        prodid,
        {:current_stock => s}
      )
    end
2f9a03aa0fcfe945229cb6126eda2cb2?d=identicon&s=25 Philip Hallstrom (Guest)
on 2007-07-25 18:56
(Received via mailing list)
> record. Well, for some reason I keep getting:
>
>        {:current_stock => s}
>      )
>    end

How come the primary key for your table is "productid" and not just "id"
?
Did you change that in your SupplierStock model?  Assuming you did...

Why arey ou creating a *new* SupplierStock when you have a prodid
instead
of *finding* the record associated with that prodid?

Save will do the right thing, but not if you try and create a *new*
record
and then set the primary key to an existing record.

I think the code you want above should be closer  to this:

product = SupplierStock.find_by_productid(prodid)
product.current_stock = s
product.save

-philip
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-07-25 19:15
(Received via mailing list)
>
> product = SupplierStock.find_by_productid(prodid)
> product.current_stock = s
> product.save
>
> -philip

Great, thanks! That fixed the second problem... any ideas on the
first? I still get a not-null constraint violation on productid on the
create call below. And yes, the primary key is defined as productid in
the SupplierStock model.

New Code:

      product = SupplierStock.find_by_productid(prodid)
      if product
        product.current_stock = s
        product.save
      else
        SupplierStock.create(
          :id      => prodid,
          :current_stock  => s
        )
      end
0a012946a32e22f4c3a5ab6866e98e45?d=identicon&s=25 Dave Smith (smitty1276)
on 2007-07-25 19:19
Could you post actual error message and the code that generates it? It
also couldn't hurt to post the relevant snippets from the
supplier_stock.rb and the migration.
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-07-25 19:40
(Received via mailing list)
On Jul 25, 11:19 am, Dave Smith <rails-mailing-l...@andreas-s.net>
wrote:
> Could you post actual error message and the code that generates it? It
> also couldn't hurt to post the relevant snippets from the
> supplier_stock.rb and the migration.
> --
> Posted viahttp://www.ruby-forum.com/.

Error occurs on the call to create:

CODE:

      product = SupplierStock.find_by_productid(prodid)
      if product
        product.current_stock = s
        product.save
      else
        product = SupplierStock.create(
          :id             => prodid,
          :current_stock  => s
        )
      end

ERROR:

Exception encountered: RuntimeError: ERROR      C23502  Mnull value in
column "productid" violates not-null constraint  FexecMain.c
L1782   ExecConstraints: INSERT INTO supplier_stock
("yesterday_stock", "current_stock") VALUES(0, 0)

SupplierStock Class:

class SupplierStock < ActiveRecord::Base

  def self.table_name()
    "supplier_stock"
  end

  def self.primary_key()
    "productid"
  end

end

Table Schema:

         Table "public.supplier_stock"
     Column      |  Type   |     Modifiers
-----------------+---------+--------------------
 productid       | integer | not null
 current_stock   | integer | not null default 0
 yesterday_stock | integer | not null default 0
Indexes:
    "supplier_stock_pkey" primary key, btree (productid)
Foreign-key constraints:
    "$1" FOREIGN KEY (productid) REFERENCES
supplier_products(productid) ON DELETE CASCADE
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2007-07-25 19:45
(Received via mailing list)
On Jul 25, 2007, at 1:14 PM, Matt White wrote:
>> and then set the primary key to an existing record.
> first? I still get a not-null constraint violation on productid on the
>         SupplierStock.create(
>           :id      => prodid,
>           :current_stock  => s
>         )
>       end

SupplierStock.find_or_create_by_productid(prodid).update_attribute
(:current_stock, s)

It will hit the database twice (select + update) or three times
(select + insert + update) depending on whether the SupplierStock
record exists or not, respectively, but if creation is relatively
rare with respect to existence, it's probably not too bad.

-Rob

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-07-25 20:10
(Received via mailing list)
Same problem with the dynamic find_by statement:

CODE:
product = SupplierStock.find_or_create_by_productid(prodid)

ERROR:
Exception encountered: RuntimeError: ERROR      C23502  Mnull value in
column "productid" violates not-null constraint  FexecMain.c
L1782   ExecConstraints: INSERT INTO supplier_stock
("yesterday_stock", "current_stock") VALUES(0, 0)
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2007-07-25 20:23
(Received via mailing list)
On Jul 25, 2007, at 1:39 PM, Matt White wrote:
>
>         )
>       end
>
> ERROR:
>
> Exception encountered: RuntimeError: ERROR      C23502  Mnull value in
> column "productid" violates not-null constraint  FexecMain.c
> L1782   ExecConstraints: INSERT INTO supplier_stock
> ("yesterday_stock", "current_stock") VALUES(0, 0)
>
> SupplierStock Class:

I think you need to let ActiveRecord know where you're departing from
convention.

> class SupplierStock < ActiveRecord::Base

   set_table_name "supplier_stock"
   set_primary_key "productid"

> Table Schema:
>     "$1" FOREIGN KEY (productid) REFERENCES
> supplier_products(productid) ON DELETE CASCADE


You might also need to do the create step like:

unless prodid.nil?
   if product = SupplierStock.find_by_id(prodid)
     product.update_attribute(:current_stock, s)
   else
     product = SupplierStock.new do |ss|
       ss.id = prodid
       ss.current_stock = s
     end
     product.save
   end
end

I don't think you can specify the :id on a create, but you can alter
the :id before the new record is saved.  In your case, however, you
seem to have prodid.nil? to start and that can't be what you expect.

-Rob

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-07-25 20:39
(Received via mailing list)
On Jul 25, 12:22 pm, Rob Biedenharn <R...@AgileConsultingLLC.com>
wrote:
> >> --
> >       else
> > L1782   ExecConstraints: INSERT INTO supplier_stock
>    set_primary_key "productid"
>
> > Indexes:
>    else
> seem to have prodid.nil? to start and that can't be what you expect.
>
> -Rob
>
> Rob Biedenharn          http://agileconsultingllc.com
> R...@AgileConsultingLLC.com

Thanks for your help Rob. Here's what I'm sticking with:

      if product = SupplierStock.find_by_productid(prodid)
        product.update_attribute(:current_stock, s)
      else
        product = SupplierStock.new { |ss|
          ss.id = prodid
          ss.current_stock = s
        }
        product.save
      end

Seems to work fine. But I still never learned why you can't specify
the id when you make a new ActiveRecord object. Here's a snipped from
my script/console with what I mean:

>> product = SupplierStock.new({:id => 600000, :current_stock => 3})
=> #<SupplierStock:0x6881cc8 @new_record=true,
@attributes={"yesterday_stock"=>0, "current_stock"=>3}>

### You can see that the ID is not included in @attributes above

>> product.id = 600000
=> 600000
>> product
=> #<SupplierStock:0x6881cc8 @new_record=true,
@attributes={"productid"=>600000, "yesterday_stock"=>0,
"current_stock"=>3}>

### But now that I specified it OUTSIDE the call to new, it is present.
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2007-07-28 07:40
(Received via mailing list)
Matt White wrote:

> Seems to work fine. But I still never learned why you can't specify
> the id when you make a new ActiveRecord object. Here's a snipped from
> my script/console with what I mean:
>
>>> product = SupplierStock.new({:id => 600000, :current_stock => 3})
> => #<SupplierStock:0x6881cc8 @new_record=true,
> @attributes={"yesterday_stock"=>0, "current_stock"=>3}>
>
> ### You can see that the ID is not included in @attributes above

The id attribute, like other attr_protected attributes, is protected
from mass assignment by hash.  You must assign it individually.

--
We develop, watch us RoR, in numbers too big to ignore.
821395fe70906c8290df7f18ac4ac6cf?d=identicon&s=25 Rick Olson (Guest)
on 2007-07-28 08:29
(Received via mailing list)
> The id attribute, like other attr_protected attributes, is protected
> from mass assignment by hash.  You must assign it individually.

make product_id just a regular indexed field and not the primary key.
Then you can change all that nonsense above to:

product = SupplierStock.find_or_create_by_product_id(600000,
:current_stock => 3)
--
Rick Olson
http://lighthouseapp.com
http://weblog.techno-weenie.net
http://mephistoblog.com
333103e4407bb5c415e5b5e9ade71f20?d=identicon&s=25 Matt White (Guest)
on 2007-08-03 00:09
(Received via mailing list)
Unfortunately, I did not define the schema - just hired into it. They
have a whole platform built on this table so changing it isn't just a
trivial thing. But at least I understand what's going on now. Thanks!
This topic is locked and can not be replied to.