# Terminal
rails g scaffold manufacture name:uniq
rails g scaffold automobiles manufacture:belongs_to name:uniq year:integer
rails g model part name:uniq price:decimal weight:decimal
rails g model automobile_part automobile:belongs_to part:belongs_to
# db/migrate/XXX_create_automobiles.rb
class CreateAutomobiles < ActiveRecord::Migration[6.0]
def change
create_table :automobiles do |t|
t.belongs_to :manufacture, null: false, foreign_key: true
t.string :name
t.integer :year, limit: 4
t.timestamps
end
add_index :automobiles, :name, unique: true
end
end
# db/migrate/XXX_create_parts.rb
class CreateParts < ActiveRecord::Migration[6.0]
def change
create_table :parts do |t|
t.string :name
t.decimal :price, precision: 8, scale: 2
t.decimal :weight, precision: 8, scale: 2
t.timestamps
end
add_index :parts, :name, unique: true
end
end
# models/automobile.rb
class Automobile < ApplicationRecord
belongs_to :manufacture
has_many :automobile_parts, dependent: :destroy
has_many :parts, through: :automobile_parts
end
# models/automobile_part.rb
class AutomobilePart < ApplicationRecord
belongs_to :automobile
belongs_to :part
end
# models/part.rb
class Part < ApplicationRecord
has_many :autombile_parts
has_many :automobiles, through: :autombile_parts
end
# views/automobiles/_form.html.erb
<div class="field">
<%= form.label :manufacture_id %>
<%= form.collection_select :manufacture_id, Manufacture.all, :id, :name, {}, { class: 'form-control' } %>
</div>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, class: 'form-control' %>
</div>
<div class="field">
<%= form.label :year %>
<%= form.number_field :year, class: 'form-control' %>
</div>
<br>
<table class='table'>
<thead>
<tr>
<th></th>
<th>Name</th>
<th class='text-right'>Price</th>
<th class='text-right'>Weight</th>
</tr>
</thead>
<tbody>
<% Part.all.each do |part| %>
<tr>
<td><%= check_box_tag "automobile[part_ids][]", part.id, form.object.parts.include?(part) %></td>
<td><%= part.name %></td>
<td class='text-right'><%= number_to_currency part.price.to_f %></td>
<td class='text-right'><%= "%.2f" % part.weight.to_f %></td>
</tr>
<% end %>
</tbody>
</tbody>
# controllers/automobiles_controller.rb
def index
@automobiles = Automobile.includes(:manufacture).all
end
private
def set_automobile
@automobile = Automobile.includes(:parts).find(params[:id])
end
def automobile_params
params.require(:automobile).permit(:manufacture_id, :name, :year, part_ids: [])
end
# views/automobiles/show.html.erb
<p>
<strong>Manufacture:</strong>
<%= @automobile.manufacture.name %>
</p>
<p>
<strong>Price:</strong>
<%= Automobiles::CalculatePrice.call(@automobile) %>
</p>
<p>
<strong>Weight:</strong>
<%= Automobiles::CalculateWeight.call(@automobile) %>
</p>
# app/services/automobiles/calculate_price.rb
module Automobiles
class CalculatePrice
# Automobiles::CalculatePrice.new(automobile).call
# Automobiles::CalculatePrice.call(automobile)
def self.call(automobile)
new(automobile).call
end
attr_accessor :automobile
def initialize(automobile)
@automobile = automobile
end
def call
automobile.parts.sum(:price)
end
end
end
# app/services/automobiles/calculate_weight.rb
module Automobiles
class CalculateWeight
# Automobiles::CalculateWeight.new(automobile).call
# Automobiles::CalculateWeight.call(automobile)
def self.call(automobile)
new(automobile).call
end
attr_accessor :automobile
def initialize(automobile)
@automobile = automobile
end
def call
automobile.parts.sum(:weight)
end
end
end