Home > OS >  RubyOnRails form.collection_select with data from second table
RubyOnRails form.collection_select with data from second table

Time:12-20

I am trying to use form.collection_select in an order form with data from a second model named products. I would like to use the field "product_reference" from the products table as selector in my HTML page. When in the order form, I want to present all product_references to the user in a selctor, let the user make his choice, take this product_reference, and store the corresponding product_id in the order form (and database table field). I have two tables, connected by id as in this schema:

  create_table "orders", force: :cascade do |t|
    t.datetime "order_date"
    t.bigint "product_id", null: false
    ...
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["product_id"], name: "index_orders_on_product_id"
  end
  create_table "products", force: :cascade do |t|
    t.string "brand"
    t.string "product_reference"
    t.string "description"
    ...
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["product_reference"], name: "index_products_on_product_reference", unique: true
  end

with the relationships described this way:

app/models/order.rb
  class Order < ApplicationRecord
    belongs_to :product
  end

app/models/ product.rb
  class Product < ApplicationRecord
    has_many :orders
  end

I used the rails console, and got exactly what I want this way:

Product.all.map(&:product_reference)
  Product Load (0.8ms)  SELECT "products".* FROM "products"
=>
["C-Beau33",
 "C-Beau50",
 ...
 "B-Volk33",
 "B-Volk66"]

In my controller I have tried to assign @prodrefs with this dezired result, which I could then use in the collection_select: Order Controller:

  # GET /orders/new
  def new
    @order = Order.new
    @prodrefs = Product.all.map(&:product_reference)
  end

I used this in my html view: app/views/orders/_form.html.erb

<%= form.collection_select :order_id, Product.all, :id, @prodrefs, :prompt => 'Select Ref' %>

and step on this error message:

["C-Beau33", "C-Beau50", ... "B-Volk33", "B-Volk66"] is not a symbol nor a string

I think this error msg is not precisely linked to my problem, when trying just to add ".to_s" I only get another error on

undefined method `#<Product::ActiveRecord_Relation:0x00007fa1087ddda8>' for #<Product id: 1, brand: "Beaufort", product_reference: "C-Beau33",...>

What has been done so far:

in an older approach with a foreign key directly on this "product_reference", I was able to use this code in my view, worked like a charm, user could select the product_reference from the pull down menu in his browser:

<%= form.collection_select :fk_prodref, Product.order(:product_reference), :product_reference, :product_reference, :prompt => 'Select Ref' %>

This fk_approach has now been rejected, cause some extensions were necessary, with new model associations.

Looking at the RubyOnRails Guide, I can find the example on cities, and the explanation in ActionView::Helpers::FormBuilder page, I see the description as:

collection_select(method, collection, value_method, text_method, options = {}, html_options = {})

So I believe my text_method is the problem here. When I translate from the guide, I come to this logic:

 collection_slct    html in city example
 method         ->  <option value=>
 collection     ->  Berlin
 value_method   ->  <select ... id="city_id">
 text_method    ->  <select name="city_id">

which let's me believe, that I want to have the 2nd row (collection) as all my product references. But I ammissing the point on the text_method then, cause the error message directs me there. Any help highly appreciated

CodePudding user response:

You're close. Kind of a mish-mash of several ways that can work, but you're close.

You can do this in a controller if you choose, though it would just be

@products = Product.all.order(:id). # or whatever order you would like

Then in your form

<%= form.collection_select( :product_id, @products, :id, :product_reference, prompt: 'Select Ref') %>
  • The first argument is the attribute you are saving, in your case, where you have order_id above, it's really product_id.
  • The section argument is the list of objects for the collection
  • The third argument is the attribute from the collection you need to save to the product_id attribute. In this case, it is id
  • The fourth argument is the attribute name you would like displayed in the dropdown, :product_reference
  • Lastly the fifth option is for the prompt
  • Related