Search code examples
ruby-on-railsrubyblockrelationshiperb

How to refer to a symbols' active record relationship inside a fields_for


Inside a fields_for block how can i reference the value of a relationship field.

For instance:

app/models/cart.rb

class Cart < ActiveRecord::Base
  attr_accessible :lineitems_attributes
  has_many :lineitems, dependent: :destroy
  accepts_nested_attributes_for :lineitems

  def total_price
    lineitems.to_a.sum { |item| item.total_price }
  end
end

app/models/lineitem.rb

class Lineitem < ActiveRecord::Base
  attr_accessible :cart_id, :quantity, :package_id, :part_id
  belongs_to :cart
  belongs_to :package
  belongs_to :part

  def total_price
    if package_id?
      return package.price * quantity
    end

    if part_id?
      return part.price * quantity
    end
  end
end

app/models/package.rb

class Package < ActiveRecord::Base
  attr_accessible :description, :img_src, :name, :price
  has_many :lineitems
end

app/views/cart/_form.html.erb

<%= form_for @cart do |f| %>
  <%= c.fields_for :lineitems do |i| %>
    <%= render 'lineitem_fields', :f => i %>
  <% end %>
  <%= c.submit %>
<% end %>

app/views/cart/_lineitem_fields.html.erb

<%= f.text_field :quantity %>

<% if :package_id? %>
  <%= f.text_field :package_id %>
<% else %>
  <%= f.text_field :part_id %>
<% end %>

<%= link_to 'Remove',
         lineitem_path(:id),
         :method => :delete,
         :confirm => t('.confirm', :default => t("helpers.links.confirm",
         :default => 'Are you sure?')) %>    

relative pieces of schema

create_table "carts", :force => true do |t|
  t.integer "branch_id"
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
end

create_table "lineitems", :force => true do |t|
  t.integer "cart_id"
  t.integer "part_id"
  t.integer "package_id"
  t.integer "quantity", :default => 1
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
end

create_table "parts", :force => true do |t|
  t.string "description"
  t.string "partNumber"
  t.decimal "price"
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
end

create_table "packages", :force => true do |t|
  t.string "description"
  t.string "name"
  t.string "img_src"
  t.decimal "price"
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
end

The above form works but...

Question 1: How to show the package.name instead of :package_id

Question 2: How to display total_price of each lineitem in the form. It is a method how would that work?

Question 3: Is there a best practice to displaying a form in an invoice looking manner where maybe the quantity is a text field but the remainder of the columns are just text or labels?

The end game scenario is this form will be a last chance to edit the quantities of the cart (or remove lineitems) before submitting an order. Obviously in the real world you want to display the quantities, package name, description and price but I can't seem to figure out how to display those values inside the form since they are in another model by relationship and not specific to lineitems.

Thanks for the help.


Solution

  • You are looking for the ActionView::Helpers::ActiveModelInstanceTag#object method. This gives you access to ActiveRecord everywhere inside the form.

    1

    <% if f.object.package_id? %>
      <%= text_field_tag :package_name, f.object.package.name %>
      <%= f.hidden_field :package_id %>
    <% else %>
    

    2 <%= f.object.total_price %>

    3 Perhaps try the :readonly => true option on all input tags except the quantity?