big time help(any idea for a proper title..)

Hey guys,

i ran in some trouble while making an important app for school, and
the deadline is so soon, that i took a desperate decision, bother
you..
I will put up the code here, and if anyone has a solution, it would
mean the world to me and my work.

My problem is this line of code li.product = cart_item.product
because list_items doesn't have a column named product, so what the
heck?

The second is that when they interrogate the db, namely the line_items
table, the product column doesn't show up, as you can see below:

sqlite3 -line db/development.sqlite3

SQLite version 3.4.0
Enter ".help" for instructions

select * from orders;

id = 1
name = Dave Thomas
address = 123 Main St
email = customer@pragprog.com
pay_type = check
created_at = 2008-06-09 13:40:40
updated_at = 2008-06-09 13:40:40

Hey guys,

i ran in some trouble while making an important app for school, and
the deadline is so soon, that i took a desperate decision, bother
you..
I will put up the code here, and if anyone has a solution, it would
mean the world to me and my work.

My problem is this line of code li.product = cart_item.product
because list_items doesn't have a column named product, so what the
heck?

I assume that list_items was a typo for line_items.

It shouldn't, it should have an integer column called product_id,
which references the key (id) of the product record

The second is that when they interrogate the db, namely the line_items
table, the product column doesn't show up, as you can see below:

> sqlite3 -line db/development.sqlite3
SQLite version 3.4.0
Enter ".help" for instructions
> select * from orders;
id = 1

This is order #1

name = Dave Thomas
address = 123 Main St
email = customer@pragprog.com
pay_type = check
created_at = 2008-06-09 13:40:40
updated_at = 2008-06-09 13:40:40
--------------------------------------------------------
> select * from line_items;
id = 1
product_id = 3

This line item belongs to product #3

order_id = 1

And it belongs to order #1

quantity = 1
total_price = 28.5
created_at = 2008-06-09 13:40:40
updated_at = 2008-06-09 13:40:40
> .quit
-------------------------------------------------------

here is the rest of the code that i have , concerning this problems:

class CreateOrders < ActiveRecord::Migration
def self.up
create_table :orders do |t|
t.string :name
t.text :address
t.string :email
t.string :pay_type, :limit => 10
t.timestamps
end
end
def self.down
drop_table :orders
end
end

class CreateLineItems < ActiveRecord::Migration
def self.up
create_table :line_items do |t|
t.integer :product_id, :null => false, :options =>
"CONSTRAINT fk_line_item_products REFERENCES products(id)"
t.integer :order_id, :null => false, :options =>
"CONSTRAINT fk_line_item_orders REFERENCES orders(id)"
t.integer :quantity, :null => false
t.decimal :total_price, :null => false, :precision => 8, :scale => 2
t.timestamps
end
end
def self.down
drop_table :line_items
end
end

This looks pretty normal, although most rails apps don't use foreign
key constraints, but I don't see a problem here.

class Order < ActiveRecord::Base
has_many :line_items

This says that Order expects the line_items table to have an integer
order_id field

end

class Product < ActiveRecord::Base
has_many :line_items

This says that Product expects the line_items table to have an integer
product_id field

# ...

class LineItem < ActiveRecord::Base
belongs_to :order

This pairs up with the association declaration in Order and also
expects that the line_items table has an order_id field

belongs_to :product

This pairs up with the association declaration in Product and also
expects that the line_items table has an product_id field

end

Other than your mistaken expectation that line_items would have a
product rather than a product_id field, I'm not sure what your problem
is.

If you need the foreign key field to be product rather than
product_id, you can use the :foreign_key option on the relevant
associations to override ActiveRecord's default, and write a migration
to rename the column. But the only reason to do this would be to
accomodate an existing non-activerecord app sharing the
database/table, and in that case you have much less freedom in
changing the DB schema.

HTH

thx a lot rick, for taking you time to answer to my problem
yeah, it was a typo it was line_items, instead of list_items.
but...still don'tget something, i'm a rails noob what would you
expect :frowning:

what does rails exactly do when you write li.product =
cart_item.product ???

and wouldn't it be more logical to write something like li.product_id
= cart_item.product_id ???

thx a lot for all your help,
radu

thx a lot rick, for taking you time to answer to my problem
yeah, it was a typo it was line_items, instead of list_items.
but...still don'tget something, i'm a rails noob what would you
expect :frowning:

what does rails exactly do when you write li.product =
cart_item.product ???

I don't know how deep you want to get but.

Each association in an active record model is represented by some form
of association proxy. the

belongs_to :product

declaration in LineItem dynamically defines two methods, I'm going to
use a mix of pseudo-code and 'real' code which is not exactly what's
there but should be a bit clearer, for details just read the
ActiveRecord code in
   lib/associations.rb, and lib/associations/belongs_to_association

def product
  # code to get the association proxy for the product association,
which will be in this case an instance of BelongsToAssociation
end

def product=(value)
  association = product # Get the association
  association.replace(value)
  association
end

And the important bit of BelongsToAssociation#replace looks like this:

      def replace(record)
        # code to deal with counter caching omitted ...

        if record.nil?
          # more counter cache code omitted
          @target = @owner[@reflection.primary_key_name] = nil
        else
          raise_on_type_mismatch(record)

          # More counter cache code omitted

          # The next line sets @target (which is the ActiveRecord
object which the record value belongs to
          # based on the value on the rhs of the 'assignment' which
is the parameter record.
          # The conditional expression deals with the fact that
          # the value could be either another proxy, as it happens to
be in the case you asked about
          # product = CartItem.product
          # or just a plain model object as it would be in eg.
          # product = Product.new(...)
          @target = (AssociationProxy === record ? record.target : record)
          # Now we set the foreign key field, but only if the value is
already saved and therefore has a primary key.
          # the primary_key_name and record_id methods deal get the
primary key names for the association, and the value
          # which may be affected by the :foreign_key option.
          # The @owner instance variable refers to the model instance
which has this BelongsToAssociation,
          # which in this case is a LineItem
          @owner[@reflection.primary_key_name] = record_id(record)
unless record.new_record?
          # The next line marks the association as dirty, so that it
will be updated when the record is saved.
          @updated = true
        end

       # this marks the association as being loaded, so that the read
accessor knows not to do a SQL request
        loaded
        record
      end

There is also some magic I won't go into which handles cases like this

    li.product = Product.new()
# Note tthis does not save the new product, so it doesn't have an id
yet, so li.product_id can't be set, until

   li.save

Which causes the Product referenced by the belongs_to association to
be saved so that the product_id field in the lineitem can be saved.

and wouldn't it be more logical to write something like li.product_id
= cart_item.product_id ???

While that's certainly possible, it isn't using AR to its value as an
Object Relational Mapper. The whole point of AR is to let you think
of models as Ruby objects rather than database tables. While you can
get closer to whats happening in the SQL, even going so far as writing
custom SQL statements, that should be done as a last resort IMHO,
although I must admit that using product_id vs. product can be useful
in some cases, and is just a small step down that slippery slope. <G>