Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hanami Architecture

Hanami Architecture

Anton Davydov

October 21, 2017
Tweet

More Decks by Anton Davydov

Other Decks in Programming

Transcript

  1. class InstitutionsController < ApplicationController load_and_authorize_resource :only => [:destroy,:edit,:new,:create,:update] before_filter :authenticate_user!,

    :except => [:student_registration, :show, :validate_registration_pin, :result, :admission, :buy_registration_pin,:paygate_callback_failure, :paygate_cancel, :paygate_pending, :paygate_callback_success, :pin_transaction_info_print] before_filter :find_institution, :except => [:show,:index, :new, :create, :semesters_for_institute_type, :start_end_date_for_assessment_period, :courses_for_batch, :paygate_callback_failure, :paygate_cancel, :paygate_pending, :paygate_callback_success, :pin_transaction_info_print] before_filter :add_bread_crumb,:except => [:show] def paygate_callback_success @pay_gate_config = YAML::load(File.open("#{Rails.root}/config/pay_gate_config.yml"))[Rails.env] @payment = TransactionRecord.find_by_order_number(params[:OrderID]) uri = URI("https://fidelitypaygate.fidelitybankplc.com/cipg/MerchantServices/UpayTransactionStatus.ashx") parameters = {:MERCHANT_ID => "#{@pay_gate_config['merchant_id']}", :ORDER_ID => "#{@payment.order_number}"} uri.query = URI.encode_www_form(parameters) result =open(uri).read result_hash = Hash.from_xml(result) record_payment_details(result_hash) if result_hash["CIPG"]["StatusCode"] == PaymentRecord::PAYMENT_SUCCESS_CODE if @payment.transactionable_type.eql?("PaymentRecord") redirect_to institution_fees_path(@payment.transactionable_type.fee.institution), :notice => "Payment transaction has been #{result_hash['CIPG']['Status']}" elsif @payment.transactionable_type.eql?("PinBuyerInfo") unless @payment.transactionable.pin_id.present? @registration = @payment.transactionable.registration @valid_registration_pin_groups = @registration.valid_registration_pin_groups @online_valid_registration_pin_groups = @valid_registration_pin_groups.where(:pin_available_type => 'Online') @offline_valid_registration_pin_groups = @valid_registration_pin_groups.where(:pin_available_type => 'Offline') @available_pin = nil @online_valid_registration_pin_groups.each do |vpg| if vpg.available_pins.present? @available_pin = vpg.available_pins.first break else next end end if !@available_pin.present? @offline_valid_registration_pin_groups.each do |vpg| if vpg.available_pins.present? @available_pin = vpg.available_pins.first break else next end end end if @available_pin.present? @payment.transactionable.pin_id = @available_pin.id @payment.transactionable.save @available_pin.is_available = false @available_pin.save @available_pin.reload if @available_pin.pin_group.pin_available_type == 'Offline' @message = "Your Order Number is #{@payment.order_number}. Please Print Transaction report to claim you PIN from Institution." else @assigned_pin = @available_pin.number @message = "Your PIN is #{@assigned_pin}. Please keep this PIN secret." end else @message = "No pin available for #{@registration.name}. Your order number is #{@payment.order_number}.Please contact with institution to get your money back if you have paid." end else pin = Pin.find @payment.transactionable.pin_id if(pin.present? && pin.pin_group.pin_available_type == 'Offline')
  2. class InstitutionsController < ApplicationController load_and_authorize_resource :only => [:destroy,:edit,:new,:create,:update] before_filter :authenticate_user!,

    :except => [:student_registration, :show, :validate_registration_pin, :result, :admission, :buy_registration_pin,:paygate_callback_failure, :paygate_cancel, :paygate_pending, :paygate_callback_success, :pin_transaction_info_print] before_filter :find_institution, :except => [:show,:index, :new, :create, :semesters_for_institute_type, :start_end_date_for_assessment_period, :courses_for_batch, :paygate_callback_failure, :paygate_cancel, :paygate_pending, :paygate_callback_success, :pin_transaction_info_print] before_filter :add_bread_crumb,:except => [:show] def paygate_callback_success @pay_gate_config = YAML::load(File.open("#{Rails.root}/config/pay_gate_config.yml"))[Rails.env] @payment = TransactionRecord.find_by_order_number(params[:OrderID]) uri = URI("https://fidelitypaygate.fidelitybankplc.com/cipg/MerchantServices/UpayTransactionStatus.ashx") parameters = {:MERCHANT_ID => "#{@pay_gate_config['merchant_id']}", :ORDER_ID => "#{@payment.order_number}"} uri.query = URI.encode_www_form(parameters) result =open(uri).read result_hash = Hash.from_xml(result) record_payment_details(result_hash) if result_hash["CIPG"]["StatusCode"] == PaymentRecord::PAYMENT_SUCCESS_CODE if @payment.transactionable_type.eql?("PaymentRecord") redirect_to institution_fees_path(@payment.transactionable_type.fee.institution), :notice => "Payment transaction has been #{result_hash['CIPG']['Status']}" elsif @payment.transactionable_type.eql?("PinBuyerInfo") unless @payment.transactionable.pin_id.present? @registration = @payment.transactionable.registration @valid_registration_pin_groups = @registration.valid_registration_pin_groups @online_valid_registration_pin_groups = @valid_registration_pin_groups.where(:pin_available_type => 'Online') @offline_valid_registration_pin_groups = @valid_registration_pin_groups.where(:pin_available_type => 'Offline') @available_pin = nil @online_valid_registration_pin_groups.each do |vpg| if vpg.available_pins.present? @available_pin = vpg.available_pins.first break else next end end if !@available_pin.present? @offline_valid_registration_pin_groups.each do |vpg| if vpg.available_pins.present? @available_pin = vpg.available_pins.first break else next end end end if @available_pin.present? @payment.transactionable.pin_id = @available_pin.id @payment.transactionable.save @available_pin.is_available = false @available_pin.save @available_pin.reload if @available_pin.pin_group.pin_available_type == 'Offline' @message = "Your Order Number is #{@payment.order_number}. Please Print Transaction report to claim you PIN from Institution." else @assigned_pin = @available_pin.number @message = "Your PIN is #{@assigned_pin}. Please keep this PIN secret." end else @message = "No pin available for #{@registration.name}. Your order number is #{@payment.order_number}.Please contact with institution to get your money back if you have paid." end else pin = Pin.find @payment.transactionable.pin_id if(pin.present? && pin.pin_group.pin_available_type == 'Offline')
  3. def call(params) FuncObject.new.call(params) do |m| m.successful? do |value| flash[:info] =

    INFO_MESSAGE redirect_to routes.tasks_path end m.failed? do |value| self.body = … end end end
  4. class Create include Dry::Transaction include Platform::Matcher Dry::Validation.load_extensions(:monads) VALIDATOR = Platform::Validation.JSON

    do # ... end step :extract step :validate step :create def extract(attributes) # ... end def validate(attributes) VALIDATOR.call(attributes).to_either end
  5. class Create include Dry::Transaction include Platform::Matcher Dry::Validation.load_extensions(:monads) VALIDATOR = Platform::Validation.JSON

    do # ... end step :extract step :validate step :create def extract(attributes) # ... end def validate(attributes) VALIDATOR.call(attributes).to_either end
  6. def initialize(object: FuncObject.new) @object = object end def call(params) result

    = @object.call(params) if result.successful? flash[:info] = INFO_MESSAGE redirect_to routes.tasks_path else self.body = … end end
  7. def initialize(object: FuncObject.new) @object = object end def call(params) result

    = @object.call(params) if result.successful? flash[:info] = INFO_MESSAGE redirect_to routes.tasks_path else self.body = … end end Dependency Injection ❤
  8. let(:action) { Create.new(object: SuccessObject.new) } it { expect(action.call(params).to eq ...

    }
 
 let(:action) { Create.new(object: FailedObject.new) } it { expect(action.call(params).to eq ... }
  9. let(:other_object) { -> (_) { nil } }
 let(:object) {

    Create.new(object: other_object) } it { expect(action.call(params).to eq ... }
  10. Pros Controlled global state
 (in one place) Memorizing instances Mocs

    for testing Resolving deps on booting project
  11. include Import[‘interactors.create_user']
 
 def call(params) result = create_user.call(params) if result[:successful]

    flash[:info] = INFO_MESSAGE redirect_to routes.tasks_path else self.body = … end end
  12. include Import[‘interactors.create_user']
 
 def call(params) result = create_user.call(params) if result[:successful]

    flash[:info] = INFO_MESSAGE redirect_to routes.tasks_path else self.body = … end end Dependency Injection ❤
  13. include Import[‘interactors.create_user']
 
 def call(params) result = create_user.call(params) if result[:successful]

    flash[:info] = INFO_MESSAGE redirect_to routes.tasks_path else self.body = … end end
  14. App App App lib One server instance App App App

    lib App App App lib App App App lib App App App lib App App App lib App App App lib App App App lib
  15. DDD

  16. – Martin Fowler “You can use a different model to

    update information than the model you use to read information”
  17. Pros • Each service isolated • All processing is in

    the background • Easy to add instances for service • Can be written on any language and you can call it from any app • Persistance
  18. Cons • Hard to understand the whole chain of events

    • Complicated • Another architecture type
 with different DB structure • Not popular in ruby