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.

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