Fungsi Generate Code
Product mempunyai attribut code dan codenya nanti akan di generate secara otomatis.Attribut ini nantinya bisa digunakan untuk barcode.
- Pada folder view/productIndex dan formnya dirubah
 - File _form.html.erb bagian user dan codenya di hilangkan
 - Untuk index.html.erb codenya seperti berikut
 - Tambahkan code pada model product
 - Selanjutnya di controller productnya tambahkan baris berikut pada method create
 - Lakukan input data di url http://localhost:3000/products/new
 
 <%= form_for(@product) do |f| %>  
  <% if @product.errors.any? %>  
   <div id="error_explanation">  
    <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>  
    <ul>  
    <% @product.errors.full_messages.each do |message| %>  
     <li><%= message %></li>  
    <% end %>  
    </ul>  
   </div>  
  <% end %>  
  <div class="field">  
   <%= f.label :name %><br>  
   <%= f.text_field :name %>  
  </div>  
  <div class="field">  
   <%= f.label :price %><br>  
   <%= f.text_field :price %>  
  </div>  
  <div class="actions">  
   <%= f.submit %>  
  </div>  
 <% end %>  
 <h1>Listing Product</h1>  
 <table class="table table-striped">  
  <thead>  
   <tr>  
    <th>Name</th>  
    <th>Code</th>  
    <th>Price</th>  
    <th></th>  
    <th colspan="3"></th>  
   </tr>  
  </thead>  
  <tbody>  
   <% @products.each do |product| %>  
    <tr>  
     <td><%= product.name %></td>  
     <td><%= product.code %></td>  
     <td><%= product.price %></td>  
     <td><%= link_to 'Show', product %></td>  
     <td><%= link_to 'Edit', edit_product_path(product) %></td>  
     <td>  
       <%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %>  
     </td>  
    </tr>  
   <% end %>  
  </tbody>  
 </table>  
 <br>  
 <%= link_to 'New Product', new_product_path %>  
  before_create :set_code  
  def generate_code(size = 6)  
   charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z}  
   (0...size).map{ charset.to_a[rand(charset.size)] }.join  
  end  
  def set_code  
   self.code = generate_code(6)  
  end  
 @product = Product.new(product_params)   
 @product.user_id = current_user.id #tambahkan code ini setelah code diatas  
Membuat Nested Form
- Edit model sale.rb tambahkan code berikut
 - Edit partial _form.html.erb di dalam folder view/sales
 - Edit aplication_helper.rb tambahkan code berikut
 - buat file partial _item_fields.html.erb di folder sales/app/views/sales/ isinya seperti berikut
 - Periksa di http://localhost:3000/sales/new hasilnya akan seperti gambar berikut
 
 has_many :items  
 accepts_nested_attributes_for :items, allow_destroy: true  
 <%= form_for(@sale) do |f| %>  
  <% if @sale.errors.any? %>  
   <div id="error_explanation">  
    <h2><%= pluralize(@sale.errors.count, "error") %> prohibited this sale from being saved:</h2>  
    <ul>  
    <% @sale.errors.full_messages.each do |message| %>  
     <li><%= message %></li>  
    <% end %>  
    </ul>  
   </div>  
  <% end %>  
  <div class="field">  
   <%= f.label :name %><br>  
   <%= f.text_field :name %>  
  </div>  
  <%= f.fields_for :items do |builder| %>   
    <%= render 'item_fields', f: builder %>   
  <% end %>   
  <%= link_to_add_fields "Add Item", f, :items %>   
  <div class="actions">  
   <%= f.submit %>  
  </div>  
 <% end %>  
 <script type="text/javascript">   
  jQuery(function() {   
   $('form').on('click', '.remove_fields', function(event) {   
   $(this).prev('input[type=hidden]').val('1');   
   $(this).closest('fieldset').hide();   
   return event.preventDefault();   
   });   
   return $('form').on('click', '.add_fields', function(event) {   
   var regexp, time;   
   time = new Date().getTime();   
   regexp = new RegExp($(this).data('id'), 'g');   
   $(this).before($(this).data('fields').replace(regexp, time));   
   return event.preventDefault();   
   });   
  });   
  </script>   
  def link_to_add_fields(name, f, association)  
   new_object = f.object.send(association).klass.new  
   id = new_object.object_id  
   fields = f.fields_for(association, new_object, child_index: id) do |builder|  
    render(association.to_s.singularize + "_fields", f: builder)  
   end  
   link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})  
  end 
 <fieldset>  
  <%= f.label :product, "Product" %>  
  <%= f.collection_select :product_id, Product.all, :id, :name %>  
  <%= f.label :quantity, "Quantity" %>  
  <%= f.text_field :quantity, class: 'padli' %>  
  <%= f.hidden_field :_destroy %>  
  <%= link_to "remove", '#', class: "remove_fields" %>  
 </fieldset>  
Fungsi Hitung Penjualan
Tadikan di form penjualan kita sudah bisa input item dan jumlahnya, tapi total penjualanya belum terhitung. Nah sekarang kita akan buat menghitung total nya:- Edit model item ketikan code berikut:
 - Edit model sale untuk menghitung total harga penjualan berikut codenya
 - Edit controllers sales_controller.rb
 - Tambahkan pada method create code berikut
 - Tambahkan parameter yang akan di permit
 - Lakukan input data penjualan http://localhost:3000/sales/new tambahkan beberapa item kemudian simpan
 - Periksa apakah total penjualanya terhitung
 - Edit file show di folder view sale
 
  before_save :set_total  
  def set_total  
   if self.quantity.blank?  
    0  
   else  
        self.total = self.quantity * self.product.price  
   end  
  end  
  def subtotal  
   if self.quantity.blank?  
    0  
   else  
        self.quantity * self.product.price  
   end  
  end  
  def subtotals  
   self.items.map { |i| i.subtotal }  
  end  
  def total_all  
   subtotals.sum  
  end  
 @sale = Sale.new(sale_params)  
 @sale.user_id = current_user.id #tambahkan ini setelah code di atas  
 @sale.total = @sale.total_all #tambahkan ini setelah code di atas  
 params.require(:sale).permit(:name, items_attributes: [:id,:product_id, :price,:quantity,:total,:_destroy])  
 <p id="notice"><%= notice %></p>  
 <p>  
  <strong>Name:</strong>  
  <%= @sale.name %>  
 </p>  
 <%= link_to 'Edit', edit_sale_path(@sale) %> |  
 <%= link_to 'Back', sales_path %>  
 <h1>Listing Item</h1>  
 <table class="table table-striped">  
  <thead>  
   <tr>  
    <th>Product</th>  
    <th>price</th>  
    <th>quantity</th>  
    <th>total</th>  
    <th></th>  
   </tr>  
  </thead>  
  <tbody>  
   <% @sale.items.each do |item| %>  
    <tr>  
     <td><%= item.product.name %></td>  
     <td><%= item.product.price %></td>  
     <td><%= item.quantity %></td>  
     <td><%= item.total %></td>  
    </tr>  
   <% end %>  
  </tbody>  
 </table>  
 <hr>  
  <p> Total </p>  
  <%= @sale.total%>  
 <hr>  
Mengatur User-Roles
Pada bagian ini kita akan mengatur hak akses user pada aplikasi POS.- Generate cancan
 - Tambahkan code di class ability.rb seperti berikut:
 - Edit products_controller tambahkan load and authorize seperti berikut
 - Edit sales_controller tambahkan load and authorize seperti berikut
 - Edit aplication_controller tambahkan baris code berikut
 - Untuk link tinggal di kasih kondisi seperti berikut
 
$ rails g cancan:ability
 class Ability  
  include CanCan::Ability  
  def initialize(user)  
   if user.present?  
    if user.role.name == 'admin'  
     can :manage, :all  
    else  
     can :create , Product  
     can :create , Sale  
     can :read, :all  
    end  
   else  
    can :read, :all  
   end  
  end  
 end  
 class ProductsController < ApplicationController  
  before_action :set_product, only: [:show, :edit, :update, :destroy]  
  load_and_authorize_resource  
  # GET /products  
  # GET /products.json  
  def index  
   @products = Product.all  
  end  
  # GET /products/1  
  # GET /products/1.json  
  def show  
  end  
  # GET /products/new  
  def new  
   @product = Product.new  
  end  
  # GET /products/1/edit  
  def edit  
  end  
  # POST /products  
  # POST /products.json  
  def create  
   @product = Product.new(product_params)  
   @product.user_id = current_user.id #tambahkan code ini setelah code diatas   
   respond_to do |format|  
    if @product.save  
     format.html { redirect_to @product, notice: 'Product was successfully created.' }  
     format.json { render :show, status: :created, location: @product }  
    else  
     format.html { render :new }  
     format.json { render json: @product.errors, status: :unprocessable_entity }  
    end  
   end  
  end  
  # PATCH/PUT /products/1  
  # PATCH/PUT /products/1.json  
  def update  
   respond_to do |format|  
    if @product.update(product_params)  
     format.html { redirect_to @product, notice: 'Product was successfully updated.' }  
     format.json { render :show, status: :ok, location: @product }  
    else  
     format.html { render :edit }  
     format.json { render json: @product.errors, status: :unprocessable_entity }  
    end  
   end  
  end  
  # DELETE /products/1  
  # DELETE /products/1.json  
  def destroy  
   @product.destroy  
   respond_to do |format|  
    format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }  
    format.json { head :no_content }  
   end  
  end  
  private  
   # Use callbacks to share common setup or constraints between actions.  
   def set_product  
    @product = Product.find(params[:id])  
   end  
   # Never trust parameters from the scary internet, only allow the white list through.  
   def product_params  
    params.require(:product).permit(:code, :name, :price, :user_id)  
   end  
 end  
 class SalesController < ApplicationController  
  before_action :set_sale, only: [:show, :edit, :update, :destroy]  
  load_and_authorize_resource  
  # GET /sales  
  # GET /sales.json  
  def index  
   @sales = Sale.all  
  end  
  # GET /sales/1  
  # GET /sales/1.json  
  def show  
  end  
  # GET /sales/new  
  def new  
   @sale = Sale.new  
  end  
  # GET /sales/1/edit  
  def edit  
  end  
  # POST /sales  
  # POST /sales.json  
  def create  
   @sale = Sale.new(sale_params)  
   @sale.user_id = current_user.id #tambahkan ini setelah code di atas   
   @sale.total = @sale.total_all #tambahkan ini setelah code di atas  
   respond_to do |format|  
    if @sale.save  
     format.html { redirect_to @sale, notice: 'Sale was successfully created.' }  
     format.json { render :show, status: :created, location: @sale }  
    else  
     format.html { render :new }  
     format.json { render json: @sale.errors, status: :unprocessable_entity }  
    end  
   end  
  end  
  # PATCH/PUT /sales/1  
  # PATCH/PUT /sales/1.json  
  def update  
   respond_to do |format|  
    if @sale.update(sale_params)  
     format.html { redirect_to @sale, notice: 'Sale was successfully updated.' }  
     format.json { render :show, status: :ok, location: @sale }  
    else  
     format.html { render :edit }  
     format.json { render json: @sale.errors, status: :unprocessable_entity }  
    end  
   end  
  end  
  # DELETE /sales/1  
  # DELETE /sales/1.json  
  def destroy  
   @sale.destroy  
   respond_to do |format|  
    format.html { redirect_to sales_url, notice: 'Sale was successfully destroyed.' }  
    format.json { head :no_content }  
   end  
  end  
  private  
   # Use callbacks to share common setup or constraints between actions.  
   def set_sale  
    @sale = Sale.find(params[:id])  
   end  
   # Never trust parameters from the scary internet, only allow the white list through.  
   def sale_params  
    params.require(:sale).permit(:name, items_attributes: [:id,:product_id, :price,:quantity,:total,:_destroy])  
   end  
 end  
  rescue_from CanCan::AccessDenied do |exception|  
   flash[:error] = "Access denied."  
   redirect_to root_url  
  end  
     <td><%= link_to 'Show', sale %></td>  
     <% if can? :update, Sale %>  
      <td><%= link_to 'Edit', edit_sale_path(sale) %></td>  
     <%end%>  
     <% if can? :destroy, Sale %>  
      <td><%= link_to 'Destroy', sale, method: :delete, data: { confirm: 'Are you sure?' } %></td>  
     <% end %>  
Public Activities
Fitur ini bertujuan untuk mencatat aktifitas user pada aplikasi. Sehingga apabila ada karyawan yang melakukan aktifitas pelanggaran / kecurangan, sistem admin bisa melihat bukti aktifitasnya.- Generate public_activity
 - Di aplication_controller.rb tambahkan code
 - Di model product.rb dan sale.rb tambahkan code berikut
 - Buat controller untuk activities
 - Di routesnya tambahkan code
 - Di controllernya tambahkan code berikut
 - Di viewnya buat file index.html.erb di folder activities isi dengan code berikut
 - Buat folder public_activity di view
 - Di dalam folder public_activity buat folder product dan sale
 - Di dalam folder product dan sale buat file html partial _create.html.erb ,_update.html.erb, _destroy.html.erb
 - Create.html.erb codenya seperti berikut
 - _update.html.erb
 - _destroy.html.erb
 - Masuk folder layout dan edit file application.html.erb tambahkan code dibawah class nav navbar-nav
 - Terakhir lakukan proses insert, update dan delete di http://localhost:3000/sales dan http://localhost:3000/products
 - Hasilnya bisa di akses di http://localhost:3000/activities
 
$ rails g public_activity:migration
$ rake db:migrate
 include PublicActivity::StoreController  
 include PublicActivity::Model  
  tracked owner: ->(controller, model) { controller && controller.current_user}  
$ rails g controller activities 
  root to: 'home#index'  
  resources :activities  
 class ActivitiesController < ApplicationController  
  def index  
   @activities = PublicActivity::Activity.order("created_at desc")  
  end  
 end  
 <h1>Listing Activities</h1>  
 <table class="table table-striped table-bordered table-condensed sortable">  
   <thead>  
     <tr>  
       <th><%= "Activities"%></th>  
     </tr>  
   </thead>  
   <tbody>  
        <% @activities.each do |activity| %>  
     <tr>  
       <td valign="top">   
         <%= activity.owner.email %>  
         <%= render_activity activity %>  
       </td>  
     </tr>  
     <% end %>  
   </tbody>  
   <tfoot>  
     <tr>  
       <td colspan="3"></td>  
     </tr>  
   </tfoot>  
 </table>  
 added product  
 <% if activity.trackable %>  
  <%= link_to activity.trackable.name, product_path(activity.trackable.id) %>  
 <% else %>  
  which has since been removed  
 <% end %>  
 Updated product  
 <% if activity.trackable %>  
  <%= link_to activity.trackable.name, product_path(activity.trackable.id) %>  
 <% else %>  
  which has since been removed  
 <% end %>  
 removed a produc  
 ·<li><%= link_to "All Activities", activities_path %></li>  


makasih pak tutorial nya
BalasHapussaya ada masalah di baris
<%= f.fields_for :items do |builder| %>
keterangan
uninitialized constant Sale::Item
tolong dibantu ya pak ? makasih :)
BalasHapusItu karena Model itemnya belum ada.
Ada yang terlewat, yaitu: baris perintah
rails g model item product:belongs_to sale:belongs_to quantity:decimal total:decimal
coba periksa kembali part 1
Thanks,
ini postingan paling menakjubkan pak, thank's a lot brother . . :)
BalasHapusditunggu postingan selanjutnya pak . .
Siap, makasih bro
HapusSangat bermanfaat
BalasHapusMakasih :)
HapusVery nice Post, sebagai tambahan, edit activities_controller.rb:
BalasHapusclass ActivitiesController < ApplicationController
def index
@activities = PublicActivity::Activity.all
end
end
Makasih Mas,
HapusIya ada yang kurang, makasih sudah diingatkan :D
Kita tambahkan sekarang
Salam,
BalasHapusTrimkasih sdh berbagi postingan yg sgt bermanfaat bagi kami pembaca.
Saya punya saran, bagaimana dibuat postingan review aplikasi yg pernah ada atau yg opensource basia ruby on rails (misalnya aplikasi pos, crm, cms, edms, dll)
Tks
Salam,
HapusThanks masukannya Mas Yudha.
Ide bagus, akan kami coba buat untuk post mendatang.
useful banget mas
BalasHapusmakasih Mas
HapusKerenn infonyaa
BalasHapussedikit saran di tutorial nya saat membuat public_activity :
BalasHapustutorial no 8 membuat folder public_activity terdapat tutorial no 9
jadi :
public_activity
----->activity
---->product
---->sale
terima kasih
Ok thanks masukan nya Mas
Hapusom saya ada masalah di error ini knp ya??
BalasHapusActionView::MissingTemplate in Sales#new
Error itu artinya kamu load view yang tidak ada.
Hapussaya ada masalah penambahan file patial item, nah file itu di taruh dmna ya???
BalasHapusdi folder sales/app/views/sales/
HapusMas mau tanya di Fungsi Hitung Penjualan bagian menambah bagian user id di sale "@sale.user_id = current_user.id" kok saya error begini ya? NoMethodError in SalesController#create
BalasHapusundefined method `id' for nil:NilClass .. Mohon infonya, trims
User login nya udah di implementasi belum Mas ?
Hapusada yg kurang gan untuk destroy nya, saya error
BalasHapusError: Cannot delete or update a parent row: a foreign key constraint fails (`sales_development`.`items`, CONSTRAINT `fk_rails_f6e50c029b` FOREIGN KEY (`sale_id`) REFERENCES `sales` (`id`)): DELETE FROM `sales` WHERE `sales`.`id` = 5
Mas Keci, error ini karena kamu mau delete data sales yang sudah ada items nya ( child data )
HapusKomentar ini telah dihapus oleh administrator blog.
BalasHapusmantap pak, lumayan buat refrensi rails di indonesia. mantap pak, ditunggu blog selanjutnya
BalasHapus