C.B.
C.B.

Reputation: 310

Adding a order to a existing customer

Hello fellow programmers, I am building a application where i can add order to a existing customer. So far so good i can add a customer. But for a week now i am stuck adding a order to the customer. I am new with rails (a month now). I have associated the Customer and ID Model. This is my code.

Update: customer_id is a foreignkey in the order table

Customer Controller

class CustomerController < ApplicationController
  def index
    @customers = Customer.sorted
  end

  def new
     @customers = Customer.new
    #hij creert een nieuwe subject
  end

  def create
     #Instantiate a new object using form paramters
    @customer = Customer.new(customer_params)
    #Save the object
    if @customer.save
    #If save succeeds, redirect to the inex acton
    flash[:notice] = "Subject created successfully"
    redirect_to(:action => 'index')
    else
    #If save fails, redisplay the form so user can fix problems
    render('new') #het zit in de new.html template
    end
  end


  def show
    @customers = Customer.find(params[:id])

  end

  def edit
    @customer = Customer.find(params[:id])
  end

  def delete
     @customer = Customer.find(params[:id])
  end

  def destroy
    customer = Customer.find(params[:id]).destroy #deze is zonder @ omdat het geen template rendert
    flash[:notice] = "Subject '#{customer.first_name}' destroyed successfully"
    redirect_to(:action => 'index')
  end

  private
  def customer_params
    params.require(:customer).permit(:first_name, :last_name)
  end
end

Order Controller

class OrderController < ApplicationController
  def index
     @order = Order.find(params[:customer_id])
  end

  def new
     @orders = Order.new
  end

 def create
  @order = Order.new(order_params)
  if @order.save
    flash[:notice] = "Subject created successfully"
    redirect_to(:action => 'index')
  else
    render 'customers/show'
  end
end

  end

  def show
   @order = Order.find(params[:customer_id]) 
  end

  def edit
  end

  def delete
  end

  private
  def order_params
    params.require(:order).permit(:customer_id, :pakket, :verstuurt)
  end

Customer Show View

<% if !flash[:notice].blank? %> 
    <div class="notice">
        <%= flash[:notice] %>
<% end %>

<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>

<div class="subjects show">
    <h2><%[email protected]_name %></h2>


    <%= link_to("View Pages", {:controller => 'order', :customer_id => @customers.id}, :class => 'action show') %>
    <%= link_to("Edit", {:action => 'edit', :id => @customers.id}, :class => 'action edit') %>
    <%= link_to("Delete",{:action => 'delete', :id => @customers.id}, :class => 'action delete') %>
    <%= link_to("Create",{:controller => 'order/create', :customer_id => @customers.id}, :class => 'action create') %>
</div>

Create a new Order to a existing customer page

<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>

<div class="subject new">
    <h2>Create Subject</h2>

    <%= form_for @order do |f| %>

    <table summary="subject form fields">
        <tr>
            <th>Package</th>
            <td><%= f.text_field(:pakket) %></td>
        </tr>
        <tr>
            <th>Sent</th>
            <td><%= f.text_field(:verstuurt) %></td>
        </tr>

    </table>

    <div class="form-buttons">
        <%= submit_tag("Create Subject") %>
    </div>

    <% end %>
</div>

Customer Model

class Customer < ActiveRecord::Base
    has_many :orders
    accepts_nested_attributes_for :orders

    scope :sorted, lambda { order("first_name ASC") }
    scope :visible, lambda { where(:visible => true) }
    scope :invisible, lambda { where(:visible => false) }
    scope :newest_first, lambda { order("customers.created_at DESC")}
    scope :search, lambda {|query|
    }
end

Order Model

class Order < ActiveRecord::Base

    belongs_to :customer

    accepts_nested_attributes_for :customer

    scope :visible, lambda { where(:visible => true) }
    scope :invisible, lambda { where(:visible => false) }
    scope :sorted, lambda { sorted("orders") }
    scope :newest_first, lambda { order("orders.created_at DESC")}
    scope :search, lambda {|query|
        where(["name LIKE ?", "%#{query}%"])}
end

Error

ActionController::ParameterMissing in OrderController#create
param is missing or the value is empty: order

Extracted source (around line #34):
32
33
34
35
36

  private
  def order_params
    params.require(:order).permit(:customer_id, :pakket, :verstuurt)
  end

Server Log

Started GET "/order/create?customer_id=9" for ::1 at 2015-11-18 14:47:40 +0100
Processing by OrderController#create as HTML
  Parameters: {"customer_id"=>"9"}
  Customer Load (0.1ms)  SELECT  "customers".* FROM "customers" WHERE "customers"."id" = ? LIMIT 1  [["id", 9]]
Completed 400 Bad Request in 2ms (ActiveRecord: 0.1ms)

ActionController::ParameterMissing (param is missing or the value is empty: order):
  app/controllers/order_controller.rb:33:in `order_params'
  app/controllers/order_controller.rb:14:in `create'


  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_source.erb (4.1ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.0ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (56.6ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.4ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (49.7ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.4ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.5ms)
  Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (111.1ms)

Upvotes: 1

Views: 840

Answers (4)

bo-oz
bo-oz

Reputation: 2872

Change your /orders/new to this:

    <%= form_for @order do |f| %>
      <table summary="subject form fields">
        <tr>
          <th>Package</th>
          <td><%= f.text_field(:pakket) %></td>
        </tr>
        <tr>
        <th>Sent</th>
          <td><%= f.text_field(:verstuurt) %></td>
      <%= f.hidden_field(:customer_id) %>
        </tr>
      </table>

  <div class="form-buttons">
    <%= f.submit %>
  </div>
<% end %>

Upvotes: 0

Richard Peck
Richard Peck

Reputation: 76774

I am new with rails (a month now).

Keep at it - you need at least 3 apps before you start to "get it". You've done extremely well so far!!


Along with the other answers, there's a more immediate concern:

param is missing or the value is empty: order

This means that you're passing parameters to your controller which are not formatted as you need. This would either suggest your form or your controller code is incorrect.

--

The first port of call is here:

<div class="form-buttons">
    <%= submit_tag("Create Subject") %>
</div>

It needs to be <%= f.submit %>

This should solve the immediate parameters error.

--

In regards to your broader question of how to associate an order to a customer, you need to look into nested resources:

#config/routes.rb
resources :customers do
   resources :orders #-> url.com/customers/:customer_id/orders/:id
end

This will allow you to do the following:

#app/controllers/orders_controller.rb
class OrdersController < ApplicationController 
   def new
      @customer = Customer.find params[:customer_id]
      @order = @customer.orders.new
   end

   def create
      @customer = Customer.find params[:customer_id]
      @order = @customer.orders.new order_params
      @order.save
   end

   private

   def order_params
      params.require(:order).permit(:pakket, :verstuurt)
   end
end

This will automatically set the foreign_key for you; allowing you to call:

#app/views/orders/new.html.erb
<%= form_for @order do |f| %>
   <%= f.text_field(:pakket) %>
   <%= f.text_field(:verstuurt) %>
   <%= f.submit %>
<% end %>

On the rare occasion that the Rails guides match the example, here's how your foreign key should look:

enter image description here

Upvotes: 1

bo-oz
bo-oz

Reputation: 2872

You need to use nested routing if you wish to create a order that's already related to the customer:

#routes.rb

resources :customers do
  resources :orders
end

This way you can make a new order for a specific customer using /customers/:customer_id/orders/new

Then in your OrderController use something like this:

def new
  @customer = Customer.find(params[:customer_id])
  @order = @customer.orders.build()
end

This way, the order is already related to the customer and the customer_id field in your form will be populated.

Edit: But this still allows creating orders for each customer without restriction. When I hear order & customer you will probably need authentication and authorization, so have a look at Devise so you can actually let a certain person order something. And when you are going to use that, you do not need the nested routes, because the customer_id will then be set just before saving.

Upvotes: 1

x6iae
x6iae

Reputation: 4164

Okay, I am not sure how you are trying to use your controller... but let us refactor your OrdersController as follow:

class OrdersController < ApplicationController
  def index
     @orders = <whatever you want it to be> # Note that I used the plural form of @orders, not @order
  end

  def new
    customer = Customer.find(params[:customer_id])
    @order = customer.order.new
  end

  def create
    @order = Order.new(order_params)
    if @order.save
      flash[:notice] = "Subject created successfully"
      redirect_to(:action => 'index')
    else
      render 'customers/show'
    end
  end

  def show
    @order = Order.find(params[:customer_id]) 
  end

  def edit
  end

  def delete
  end

  private
  def order_params
    params.require(:order).permit(:customer_id, :pakket, :verstuurt)
  end
end

And then, in your form for order:

<%= form_for @order do |f| %>
  <table summary="subject form fields">
    <tr>
      <th>Package</th>
      <td><%= f.text_field(:pakket) %></td>
    </tr>
    <tr>
    <th>Sent</th>
      <td><%= f.text_field(:verstuurt) %></td>
    </tr>
  </table>

  <div class="form-buttons">
    <%= f.submit %>
  </div>
<% end %>

This should work fine for you.

Upvotes: 1

Related Questions