Search code examples
ruby-on-rails-4controllerdecimalparametersnested-form-for

All parameters in this create method are being inserted in the db; except for one. Is it an issue with nested form or the datatype?


I am new to ruby on rails and coding in general. I wrote a nested form_for where the Price class belongs to an Item class. The values :amount, :timeframe, and :item_id are to be stored through the controller. After the action ends only the :timeframe and :item_id are stored but not the :amount value.

Does this have to do with:

  • The nested form?

  • The datatype, and or precision & scale details for :amount?

  • Could it also be an issue with my controller method?

Any clarification would be greatly appreciated!

Here is the form:

<%= form_for @item, html: {multipart: true}  do |f| %>

    <div class="main-form">
        <div class="new-item-form">
            <%= f.label :title %>
            <%= f.text_field :title %>
        </div>

        <div class="new-item-form">
            <%= f.label :description %>
            <%= f.text_field :description %>
        </div>

        <div class="new-item-form">
            <%= f.label :deposit %>
            <%= f.text_field :deposit %>
        </div>

        <div class="new-item-form">
            <%= f.label :tags %>
            <%= f.text_field :tags %>
        </div>

        <div class="new-item-form">
            <%= f.label :image  %>
            <%= f.file_field :image  %>
        </div>

        <%= fields_for :price do |f| %>
        <div class="new-item-form">
            <%=f.label :timeframe %>
            <%= select_tag(:timeframe, options_for_select([["Hour"],["Day"],["Week"]])) %>
        </div>

        <div class="new-item-form">
            <%=f.label :amount %>
            <%=f.number_field :amount %>
        </div>
        <% end %>

    <%= f.submit %>
<%end%>

This is the controller:

class ItemsController < ApplicationController
def show
    @item = Item.find(params[:id])
    @price = Price.where(item_id: @item.id).first
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(item_params)
    if @item.save
    @price = Price.create(:timeframe => params[:timeframe], :amount => params[:amount], :item_id => @item.id)
    @price.save
      redirect_to @item, notice: "Item Successfully Added!"
    else
      flash[:message] = "Something did not validate"
      render 'new'
    end
  end

  private
  def item_params
    params.require(:item).permit(:title, :description, :image, :user_id, :deposit, :tags)
  end

end

Additional documents include the Item model and Price model:

class Item < ActiveRecord::Base
    validates :title, :description, :deposit, :tags,  presence: true

    belongs_to :user

    has_many :prices, :dependent => :destroy
    has_many :reviews, :dependent => :destroy
    has_many :ratings, :dependent => :destroy
    has_many :users_that_reviewed_this, through: :reviews, source: :user
    has_many :users_that_rated_this, through: :ratings, source: :user
end

class Price < ActiveRecord::Base
belongs_to :item end

As well as the database schema for these classes:

create_table "items", force: :cascade do |t|
    t.string   "title"
    t.string   "description"
    t.string   "image"
    t.integer  "user_id"
    t.integer  "deposit"
    t.string   "type"
    t.string   "tags"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  create_table "prices", force: :cascade do |t|
    t.string   "timeframe"
    t.decimal  "amount"
    t.integer  "item_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

Solution

  • The problem in your code is in params[:amount]. No params are there, it should be params[:price][:amount]. It will work this way!

    Though the approach is not the most "conventional" Here is the correct approach using accepts_nested_attributes, adding prices_attributes to strong_parameters and using

    In your model

    class Item < ActiveRecord::Base
        validates :title, :description, :deposit, :tags,  presence: true
    
        belongs_to :user
    
        has_many :prices, dependent: :destroy
        has_many :reviews, dependent: :destroy
        has_many :ratings, dependent: :destroy
        has_many :users_that_reviewed_this, through: :reviews, source: :user
        has_many :users_that_rated_this, through: :ratings, source: :user
    
        accepts_nested_attributes_for :prices, reject_if: :all_blank, allow_destroy: true
    
    end
    

    In your controller

    def create
        @item = Item.new(item_params)
        @item.prices.build
        if @item.save
          redirect_to @item, notice: "Item Successfully Added!"
        else
          flash[:message] = "Something did not validate"
          render 'new'
        end
      end
    
     private
     def item_params
        params.require(:item).permit(:title, :description, :image, :user_id, :deposit, :tags, prices_attributes: [:timeframe, :amount])
      end
    

    In your view

    <%= form_for @item, html: {multipart: true}  do |f| %>
    
        <div class="main-form">
            <div class="new-item-form">
                <%= f.label :title %>
                <%= f.text_field :title %>
            </div>
    
            <div class="new-item-form">
                <%= f.label :description %>
                <%= f.text_field :description %>
            </div>
    
            <div class="new-item-form">
                <%= f.label :deposit %>
                <%= f.text_field :deposit %>
            </div>
    
            <div class="new-item-form">
                <%= f.label :tags %>
                <%= f.text_field :tags %>
            </div>
    
            <div class="new-item-form">
                <%= f.label :image  %>
                <%= f.file_field :image  %>
            </div>
    
            <%= f.fields_for :prices, Price.new do |p| %>
            <div class="new-item-form">
                <%=p.label :timeframe %>
                <%= p.select(:timeframe, [["Hour"],["Day"],["Week"]], :prompt => 'Select') %>
            </div>
    
            <div class="new-item-form">
                <%=p.label :amount %>
                <%=p.number_field :amount %>
            </div>
            <% end %>
    
        <%= f.submit %>
    <%end%>