luissimo
luissimo

Reputation: 978

Select column from different model and show attributes in view

I have a scaffolded 'Customer.rb' model and a 'Invoice.rb' model. I want people to select a existing Customer from the Customer model and put a few attributes of that selected option in the view of the invoice.

This is the code inside my Invoice#new (@customer = Customer.all in the Invoice_controller)

                <%= @customer.select(:company_name) do |f| %>
                    <h4>Customer:</h4>
                    <div class="well">
                      <address>
                        <strong class="text-dark"><%= f.company_name %></strong><br/>
                        <%= f.first_name + f.last_name if f.first_name.present? && f.last_name.present?%><br/>
                        <%= f.address_line_1 %><br/>
                        <%= f.address_line_2 if present? %>
                      </address>
                    </div>
                <% end %>
              </div>

Invoices Controller

class InvoicesController < ApplicationController
  before_action :set_invoice, only: [:show, :edit, :update, :destroy]

  # GET /invoices
  # GET /invoices.json
  def index
    @invoices = Invoice.all
  end

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

  # GET /invoices/new
  def new
    @invoice = Invoice.new
    @customer = Customer.all
  end

  # GET /invoices/1/edit
  def edit
  end

  # POST /invoices
  # POST /invoices.json
  def create
    @invoice = Invoice.new(invoice_params)

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

  # PATCH/PUT /invoices/1
  # PATCH/PUT /invoices/1.json
  def update
    respond_to do |format|
      if @invoice.update(invoice_params)
        format.html { redirect_to @invoice, notice: 'Invoice was successfully updated.' }
        format.json { render :show, status: :ok, location: @invoice }
      else
        format.html { render :edit }
        format.json { render json: @invoice.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /invoices/1
  # DELETE /invoices/1.json
  def destroy
    @invoice.destroy
    respond_to do |format|
      format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def invoice_params
      params.require(:invoice).permit(:number, :currency, :date, :duedate, :btwtotal, :subtotal, :total, :footer)
    end
end

This shows the correct information but it shows it for ALL columns in the Customers table. I wan't people to pick a specific column only. Like lets say; someone selects 'Coca Cola Ltd.' from a dropdown and then sees only the information of Coca Cola Ltd. (f.company_name: Coca Cola Ltd. etcetera)

The Invoice.rb model contains 'has_one :customer'
The Customer.rb model contains 'belongs_to :invoice'

I tried everything from the ruby on rails guides but i don't seem to get it. Any help would be MUCH appreciated

UPDATE

Invoices#_form

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

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


<div class="container-fluid container-fullw">
  <div class="row">
    <div class="col-md-8">
      <div class="panel panel-white">
        <div class="panel-body">
          <div class="invoice">
            <div class="row invoice-logo">
              <div class="col-sm-6">
                <img alt="" src="">
              </div>
              <div class="col-sm-6">
                <p class="text-dark">
                  <%= @invoice.number %> <small class="text-light"> 23-07-2016 </small>
                </p>
              </div>
            </div>
            <hr>
            <div class="row">
              <div class="col-sm-4">
                <%= f.select :customer, :customer_id, options_for_select(@customers.map{ |customer| [customer.company_name, customer.id, {"data-some-field" => customer.company_name}] },
                                                                         id: "my_select") %>
                    <h4>Klant:</h4>
                    <div class="well">
                      <address>
                        <strong class="text-dark"></strong><br/>
                        <%= f.text_field :company_name, id: "my_field" %>
                        <br>
                        <abbr title="Phone">P:</abbr> (123) 456-7890
                      </address>
                      <address>
                        <strong class="text-dark">E-mail:</strong>
                        <a href="mailto:#"> [email protected] </a>
                      </address>
                    </div>
              </div>
              <div class="col-sm-4 pull-right">
                <h4>Gegevens:</h4>
                <ul class="list-unstyled invoice-details padding-bottom-30 padding-top-10 text-dark">
                  <li>
                    <strong>BTW #:</strong> 233243444
                  </li>
                  <li>
                    <strong>Bedrijfsnaam:</strong> Company B.V
                  </li>
                  <li>
                    <strong>IBAN:</strong> 1233F4343ABCDEW
                  </li>
                  <li>
                    <strong>Factuurdatum:</strong> 01/01/2016
                  </li>
                  <li>
                    <strong>Te betalen voor:</strong> 11/02/2016
                  </li>
                </ul>
              </div>
            </div>
            <div class="row">
              <div class="col-sm-12">
                <table class="table table-striped">
                  <thead>
                  <tr>
                    <th> # </th>
                    <th> Item </th>
                    <th class="hidden-480"> Description </th>
                    <th class="hidden-480"> Quantity </th>
                    <th class="hidden-480"> Unit Cost </th>
                    <th> Total </th>
                  </tr>
                  </thead>
                  <tbody>
                  <tr>
                    <td> 1 </td>
                    <td> Lorem </td>
                    <td class="hidden-480"> Drem psum dolor </td>
                    <td class="hidden-480"> 12 </td>
                    <td class="hidden-480"> $35 </td>
                    <td> $1152 </td>
                  </tr>
                  <tr>
                    <td> 2 </td>
                    <td> Ipsum </td>
                    <td class="hidden-480"> Consectetuer adipiscing elit </td>
                    <td class="hidden-480"> 21 </td>
                    <td class="hidden-480"> $469 </td>
                    <td> $6159 </td>
                  </tr>
                  <tr>
                    <td> 3 </td>
                    <td> Dolor </td>
                    <td class="hidden-480"> Olor sit amet adipiscing eli </td>
                    <td class="hidden-480"> 24 </td>
                    <td class="hidden-480"> $144 </td>
                    <td> $8270 </td>
                  </tr>
                  <tr>
                    <td> 4 </td>
                    <td> Sit </td>
                    <td class="hidden-480"> Laoreet dolore magna </td>
                    <td class="hidden-480"> 194 </td>
                    <td class="hidden-480"> $317 </td>
                    <td> $966 </td>
                  </tr>
                  </tbody>
                </table>
              </div>
            </div>
            <div class="row">
              <div class="col-sm-12 invoice-block">
                <ul class="list-unstyled amounts text-small">
                  <li>
                    <strong>Subtotaal:</strong>
                    <div class="field">
                    <%= f.text_field :subtotal %>
                  </div>
                  </li>
                  <!-- <li>
                     <strong>Discount:</strong>
                   </li> -->
                  <li>
                    <strong>BTW:</strong>
                    <div class="field">
                      <%= f.text_field :btwtotal %>
                    </div>
                  </li>
                  <li class="text-extra-large text-dark margin-top-15">
                    <strong >Totaal:</strong>
                    <div class="field">
                      <%= f.text_field :total %>
                    </div>
                  </li>
                </ul>
                <br>
              </div>
            </div>
          </div>
          <div class="panel-footer">
            <%= @invoice.footer.present? ? @invoice.footer : "We verzoeken u vriendelijk het bovenstaande bedrag van
            € #{@invoice.total} voor #{@invoice.duedate} te voldoen op onze bankrekening onder vermelding van het
            factuurnummer #{@invoice.number}. Voor vragen kunt u contact opnemen per e-mail." %>
          </div>
        </div>
      </div>
    </div>
    <div class="col-md-4">
      <div class="panel panel-white">
        <div class="panel-body">
          <div class="form-group">
            <div class="field">
              <%= f.label :Factuurnummer %><br>
              <%= f.text_field :number, placeholder: '2016-0001' %>
            </div>
            <div class="form-group">
              <%= f.label :Munteenheid %><br>
              <%= f.select(:currency, [[' €', 1, title: 'Euro', value: 'EURO'], [' $', 2, title: 'US Dollar', value: 'USD'],
                                       [' £', 3, title: 'GBP Pound', value: 'GBP']]) %>
            </div>
            <div class="field">
              <%= f.label :factuurdatum %><br>
              <%= f.date_select :date %>
            </div>
            <div class="field">
              <%= f.label 'te betalen voor' %><br>
              <%= f.date_select :duedate %>
            </div>
            <div class="field">
              <%= f.label :footer %><br>
              <%= f.text_area :footer %>
            </div>
            <div class="actions">
              <%= f.submit 'opslaan', class: 'btn btn-primary btn-success' %>
              <%= link_to 'annuleren', invoices_path, class: 'btn btn-primary btn-info' %>
              <a onclick="javascript:window.print();" class="btn btn-primary float-right"> print <i class="fa fa-print"></i></a>
            </div>
            <% end %>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<!-- end: INVOICE -->

<script>
  $("#my_select").change(function() {
    var selection = $(this).find(":selected");
    alert(selection.data("data-some-field"));
  });
</script>

Upvotes: 0

Views: 113

Answers (2)

MarsAtomic
MarsAtomic

Reputation: 10696

What you want is more complicated than you might have imagined. Anytime you want dynamic stuff going on, you're going to have to rely on scripting. The view is largely inert -- it's only displaying information supplied to it by the controller, so you're going to need help from JavaScript and potentially AJAX.

Firstly, pluralize your field name in invoice#new to save potential confusion for people viewing your code.

@customer = Customer.all

should be:

@customers = Customer.all

This way, it's clear that you're referring to a collection and not a single record.

Then replace your select in the view with the following:

<%= f.select :customer, options_for_select(@customers.map { | cust | [cust.name, cust.id, 'data-some-field' => cust.some_field] }), { id: "my_select" } %>

What you're doing here is passing the select an options_for_select that uses an HTML data attribute to pass in additional information. You're going to have to modify invoice#new to build this information, an exercise I leave to you because I have no idea what you wish to display.

Add a textfield to your view to display the new information:

text_field_tag (:some_field, id: "my_field")

Then, you're going to have to modify your invoice.js asset with the following JavaScript:

$("#my_select").change(function()
{
    var selection = $(this).find(":selected");
    getElementById("my_field").value = selection.data("data-some-field");
});

Upvotes: 1

Prince Abalogu
Prince Abalogu

Reputation: 395

I would say you should associate both with a join table.. the join table will keep record of both customer and invoice id eg

class Customer < ApplicationRecord
has_many :join_table 
has_many :invoices, :through => :join_table 
end 

class Invoice < ApplicationRecord
has_many :join_table
has_many :customers, :through => :join_table
end 

class JoinTable < ApplicationRecord
belongs_to :invoice
belongs_to :customer
end  

and then in both Invoice and Customer create action you put

def create
@invoice = Invoices.new(invoice_params) 
if @invoice.save
  @invoice.customers << Customer.all
    redirect_to @invoice
else 
    render new 
end         

end

This will create join table objects that will link every customer with an invoice with their ids

Then tweak the join_table.rb model

class JoinTable < ActiveRecord::Base
after_create :add_customer_values

def add_customer_values 
customer = Customer.find self.customer_id
self.value1 = customer.value1
self.value2 = customer.value2
self.save 
end 

and then you should have a list of all customers in the invoice show page and display the join_table record as a dummy but same values

Upvotes: 1

Related Questions