Is there a more efficient way to work dropdowns from other t

Hi, all.

Just wondering if there is a better dry way to do this:

I have an inventory program, that I'm writing to learn rails. It has
multiple tables, one of the main ones is called parts. Parts has name,
manufacturer, vendor, etc columns.
Manufacturer and vendor columns are just storing ids of records from
tables Manufacturers and Vendors. So when I'm creating a form in the
view for "new" action with the dropdowns I need to first get data from
those two table in my controller then iterate in my view to show all the
options in the dropdown. This is all fine. My question is - when I save
the form it complains that I have no @vendors and @manufacturers in my
create method. So I have to do @vendors = Vendor.find(:all) again.

It's not a big performance hit, since I only might have potentially 50
records in each table, but it seems to me I should be able to do
@vendors = Vendor.find(:all) once in my controller and then use that in
many actions.

Please advise. Below are snippets from my code (please excuse crudity):

Controller

Code :

   1. def new
   2. @vendors = Vendor.find(:all)
   3. @manufacturers = Manufacturer.find(:all)
   4. @departments = Department.find(:all)
   5. part_status_type = StatusType.find_by_name("part status").id
   6. @part_statuses =
Status.find_all_by_status_type(part_status_type)
   7. @part = Part.new
   8. end
   9.
  10. def edit
  11. end
  12.
  13. def create
  14. @vendors = Vendor.find(:all)
  15. @manufacturers = Manufacturer.find(:all)
  16. @departments = Department.find(:all)
  17. part_status_type = StatusType.find_by_name("part status").id
  18. @part_statuses =Status.find_all_by_status_type(part_status_type)
  19. @part = Part.new(params[:part])
  20. if @part.save
  21. flash[:notice] = 'Part with id <strong>#' + @part.id.to_s +
'</strong> added successfully'
  22. redirect_to parts_path
  23. else
  24. render :action => 'new'
  25. end
  26. end

View

Code :

   1. <tr bgcolor="#cccccc">
   2. <td>Vendor</td>
   3. <td>Vendor part #</td>
   4. </tr>
   5. <tr bgcolor="#ffffff">
   6.
   7. <td>
   8. <%= collection_select("part", "vendor", @vendors, "id",
"name") %>
   9. </td>
  10. <td><%= f.text_field :vendor_specific_id %></td>
  11. </tr>
  12. <tr bgcolor="#cccccc">
  13. <td>Manufacturer</td>
  14. <td>Manufacturer part #</td>
  15. </tr>
  16. <tr bgcolor="#ffffff">
  17. <td>
  18. <%= collection_select("part", "manufacturer", @manufacturers,
"id", "name") %>
  19. </td>
  20. <td><%= f.text_field :manufacturer_specific_id %></td>
  21. </tr>

def create
  @part = Part.new(params[:part])
  if @part.save
    flash[:notice] = 'Part with id <strong>#' + @part.id.to_s + '</

added successfully'

    redirect_to parts_path
  else
    @vendors = Vendor.find(:all)
    @manufacturers = Manufacturer.find(:all)
    @departments = Department.find(:all)
    part_status_type = StatusType.find_by_name("part status").id
    @part_statuses =Status.find_all_by_status_type(part_status_type)
    render :action => 'new'
   end
end

The reason for this is the render :action => 'new business. You see,
when you create a part, there are 2 ways to go; either you are
succesfull or not. If you are then everything is groovy and you
redirect_to wherever, the redirect_to, disposes of all your variables
(@part, @vendors...) and calls the new action method as if it was the
first time. If its not succesfull however, we cant redirect_to because
wed loose all the data that the user put in in the first place and
restart with a blank form. So we render, which means, grab the view,
and render it as if i was that method but do not call the method. that
is why you need to initialize the variables again, thats why ive put
them in the else statement, so that they only get loaded if you are
not succesfull.

try this, remove the "duplicate" varianble assignments and create a
part that is succesfull, it wont complain.

The reason for this is the render :action => 'new business. You see,
when you create a part, there are 2 ways to go; either you are
succesfull or not. If you are then everything is groovy and you
redirect_to wherever, the redirect_to, disposes of all your variables
(@part, @vendors...) and calls the new action method as if it was the
first time. If its not succesfull however, we cant redirect_to because
wed loose all the data that the user put in in the first place and
restart with a blank form. So we render, which means, grab the view,
and render it as if i was that method but do not call the method. that
is why you need to initialize the variables again, thats why ive put
them in the else statement, so that they only get loaded if you are
not succesfull.

try this, remove the "duplicate" varianble assignments and create a
part that is succesfull, it wont complain.

Thanks "Wolas!"

It does help in this particular case. But I was also wondering in
general what's the best way or any other way to do? Globals?

A better example might be with these 2 tables:

class CreatePurchaseOrders < ActiveRecord::Migration
  def self.up
    create_table :purchase_orders do |t|
    t.string :status_id
    t.integer :submitted_by
    t.integer :ordered_by
    t.integer :approved_by
    t.text :comments
    t.integer :vendor_id
    t.string :vendor_specific_po_id

      t.timestamps
    end
  end

  def self.down
    drop_table :purchase_orders
  end
end

orders_by, submitted_by, and approved_by - all refer to Users table -
and potenttially one person, or multiple so how do I setup association
in this case?

A better example might be with these 2 tables:

class CreatePurchaseOrders < ActiveRecord::Migration
def self.up
create_table :purchase_orders do |t|
t.string :status_id
t.integer :submitted_by
t.integer :ordered_by
t.integer :approved_by
t.text :comments
t.integer :vendor_id
t.string :vendor_specific_po_id

  t\.timestamps
end

end

def self.down
drop_table :purchase_orders
end
end

orders_by, submitted_by, and approved_by - all refer to Users table -
and potenttially one person, or multiple so how do I setup association
in this case?

You can add many belongs_to clauses with different names all referring
to the same class:

class PurchaseOrder < AR::Base
  belongs_to :submitter, :class_name => "User", :foreign_key
=> :submitted_by
  belongs_to :orderer, :class_name => "User", :foreign_key
=> :ordered_by
  belongs_to :approver, :class_name => "User", :foreign_key
=> :approved_by
end

and then it's possible to make the following queries on a
@purchase_order instance:
@purchase_order.submitter # => the user that is referenced by
submitted_by.

http://www.spacevatican.org/2008/5/6/creating-multiple-associations-with-the-same-table

The convention in rails would be for submitted_by etc... to be submitted_by_id and for the association to be submitted_by (weird shit happens if an association and a column have exactly the same name)
Fred