0
votes

Updated version - I have taken the initial advice provided (thanks for that!) but I'm still having the same issue. I have updated everything below.

I have two models, products that belong to a store.

I'm attempting to display a related object's column (Store.name) in a couple of views for products that belong to a store and can't seem to get the store to save correctly. Please note: Still very new to this and learning.

Model for Product:

    class Product < ActiveRecord::Base

        belongs_to :store
        validates_presence_of :name, :url, :price


    end

Model for Store:

class Store < ActiveRecord::Base

has_many :products
has_many :pins, through: :products
accepts_nested_attributes_for :products

end

Controller for Product:

class ProductsController < ApplicationController before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
    @stores = Store.all


  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render action: 'show', status: :created, location: @product }
      else
        format.html { render action: 'new' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:name, :description, :imageurl, :url, :price, :Store_id)
    end
end

Form for products

   <%= form_for(@product) do |f| %>
    <% if @product.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>

        <ul>
        <% @product.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
        </ul>
      </div>
    <% end %>

    <div class="form-group">
      <%= f.label :name, "Name" %>
      <%= f.text_field :name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :description, "Description" %>
      <%= f.text_area :description, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :imageurl, "Image" %>
      <%= f.text_field :imageurl, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :url, "Web Address" %>
      <%= f.text_field :url, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :price, "Price" %>
      $<%= f.text_field :price, class: "form-control" %>
    </div>

  <div class="form-group">
  <%= collection_select(:product, :Store_id, Store.all, :id, :name, {:prompt=> "Select A Store"}, {:class => "form-control"} ) %>



  </div>
  <div class="form-group">
       <%= f.submit class: "btn btn-primary" %>
    </div>
  <% end %>

  <%= params.inspect %>

View for products (show.html.erb):

<p id="notice"><%= notice %></p>

    <p>
      <strong>Name:</strong>
      <%= @product.name %>
    </p>

    <p>
      <strong>Description:</strong>
      <%= @product.description %>
    </p>

    <p>
      <strong>Store Id:</strong>
      <%= @product.Store_id %>
    </p>

    <p>
      <strong>Store Name:</strong>
      <%= @product.store.try(:name) %>
    </p>


    <p>
      <strong>Image:</strong>
      <%= @product.imageurl %>
    </p>

    <p>
      <strong>Url:</strong>
      <%= @product.url %>
    </p>

    <p>
      <strong>Price:</strong>
      $<%= @product.price %>
    </p>

    <%= params.inspect %>

    <%= link_to 'Edit', edit_product_path(@product) %> |
    <%= link_to 'Back', products_path %>

You'll notice that I have .try in place where I'm referencing product.store.name from product.store so that I stop getting the error listed in the subject of this post.

When I look up the product I'm viewing using the console I see that Store_id: 2

When I look up the store with id of 2 I see that Store_id: 1 - so there is a value present there.

I printed params on the show view and only get this: {"action"=>"show", "controller"=>"products", "id"=>"2"}.

Can anyone find what I'm missing in this whole set up to get product.store.name to display in my product views? Let me know if I can provide more info!

2

2 Answers

1
votes

First, you should be using snake_case for attributes. UpperCamelCase is reserved for constant names in Ruby, that includes things like classes and modules. Update your code to not use UpperCamelCase style naming for attributes (eg. ProdDesc, ProdImageUrl). Also it is unnecessary to use prefixes like Prod* for attributes.

So instead of

class Product < ActiveRecord::Base
  belongs_to :store
  validates_presence_of :ProdTitle, :ProdUrl, :ProdPrice
end

Your class will look like this:

class Product < ActiveRecord::Base
  belongs_to :store
  validates_presence_of :title, :url, :price
end

You can read more about Ruby and Rails naming conventions here:

I suspect that this causes the problem. You will also need to rename columns in database and change your controller and view code to reflect the change. If you can, please start again with your application.

0
votes

You have taken name for field In database which are non conventional. By default The active record looks for store_id field in product table . Field name in a table should be snake case .so now you have to explicitly tell in product model the foreign key for store model