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>