alcafar
alcafar

Reputation: 53

Virtual attribute in Ruby on Rails

I am a newbie in Rails. I am not understanding what I'm doing wrong here.

I have the following model order.rb, with a virtual attribute value:

    class Order < ActiveRecord::Base
      ACTIONS = %w(buy sell)
      ORDER_TYPES = %w(LMT STP)
      TIFS = %w(DAY GTC OPG IOC)

      attr_accessible :action, :price, :quantity, :symbol, :tif, :order_type, :value

      validates :action, :symbol, :tif, :order_type, presence: true
      validates :price, numericality: { greater_than_or_equal_to: 0.0001 }
      validates :quantity, numericality: { only_integer: true, greater_than: 0 }
      validates :action, inclusion: ACTIONS
      validates :order_type, inclusion: ORDER_TYPES
      validates :tif, inclusion: TIFS

      def value
        price * quantity
      end

      def value= (val)
        self.quantity = val / self.price
      end
    end

This model works fine in rails console, where I can set value and it calculates quantity.

The problem is when I try to visualize the form. app/views/orders/new.html.erb renders the following _form.html.erb:

    <%= form_for @order, html: { :class => 'form-inline' } do |f| %>
      <% if @order.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@order.errors.count, "error") %> prohibited this order from being saved:</h2>

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

      <fieldset>
      <legend><%= params[:action].capitalize %> Order</legend>

      <table class="table">
        <thead>
          <tr>
            <th><%= f.label :action %></th>
            <th><%= f.label :symbol %></th>
            <th><%= f.label :price %></th>
            <th><%= f.label :value %></th>
            <th><%= f.label :order_type %></th>
            <th><%= f.label :tif, "TIF" %></th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><%= f.select :action, Order::ACTIONS, {}, class: 'input-small' %></td>
            <td><%= f.text_field :symbol, class: 'input-small' %></td>
            <td><%= f.text_field :price, class: 'input-small' %></td>
            <td><%= f.text_field :value, class: 'input-small' %></td>
            <td><%= f.select :order_type, Order::ORDER_TYPES, {}, class: 'input-small' %></td>
            <td><%= f.select :tif, Order::TIFS, {}, class: 'input-small' %></td>
          </tr>
        </tbody>
      </table>

      <%= f.submit "Submit", class: "btn btn-primary" %>
      <%= f.submit "Clear", class: "btn", type: "reset" %>

      </fieldset>
    <% end %>

I get an error when I open the page in the browser, raised on the line of _form.html.erb with the text field value:

NoMethodError in Orders#new undefined method `*' for nil:NilClass

What am I doing wrong? I tried to follow http://railscasts.com/episodes/16-virtual-attributes

Upvotes: 0

Views: 670

Answers (1)

Soundar Rathinasamy
Soundar Rathinasamy

Reputation: 6728

For the newly built order object price is nil. So you are getting this error.

Before calculating value make sure that you have price and quantity

  def value
    return unless price || quantity
    price * quantity
  end

Upvotes: 3

Related Questions