Feeds:
Posts
Comments

This is a very simple superclass for service objects, its purpose is to rollback any changes that happen when a service throws a non-catched exception up to the whole services call chain, (A calls B, B calls C, C calls D,…), it does that by two parts:
– Rolling DB changes: Wrapping all services calls in DB transacion
– Non DB changes: Add service specific non DB-changes that needs to be rolled back in a rollback method (like deleting a text file)

class BaseService

  def execute
    ApplicationRecord.transaction do
      begin
        _execute
      rescue Exception => e
        rollback
        raise e
      end
    end
  end

  private

  # To be implemented in subclassesn
  def _execute
    raise NotImplementedError
  end

  # To be implemented in subclasses if needed. I
  # Rollback changes other than DB changes (like API calls that modifies something)
  def rollback
  end

end

# Example
module Orders
  class CreateService < BaseService
    attr_reader :current_user, :params

    def initialize(current_user, params)
      @current_user = current_user
      @params = params
    end

    private

    def _execute
      # modify some non DB resource(e.g. writing a text file)
      File.write(output_file_path, "Some data")

      # DB changes
      order = Order.create(params)
      order
    end

    def rollback
      File.delete(output_file_path) if File.exists?(output_file_path)
    end

    def output_file_path
      "path/to/file"
    end

  end
end
Advertisements

Today I faced the task to save documents using rails paperclip saving them in AWS S3, however I needed to this in background
in order not to block the user. I didn’t want to use delayed_paperclip as it is used with only delayed_job or Resque, I wanted
something that will run on all ActiveJob adapters.

My idea is inspired originally by https://airbladesoftware.com/notes/asynchronous-s3/ , however that solution has points that can be enhanced: you need to create another local attachment for each attachment you add to your model, you may forget to add a migration to create it, you may forget to add it to the model, and finally: it add more columns to your model than needed.

The idea I used is as follows:
– Before saving the attachment, change the storage to Filesystem, so that it will write the document locally -not in public directory-, not to S3
– After saving the attachment, create a background process to post the document to AWS S3

The code is very basic so it can be enhanced, however this is the basic idea which is working fine till now.

# in your model like this
has_attached_file :attachment, process_in_background: true
# use paperclip normally, you don't have to do/change anything!
my_model.attachment = some_file 


# Put this code in intializers directroy
module Extensions
  module Paperclip
    module Attachment
      attr_accessor :uploading_to_s3

      def uploading_to_s3?
        uploading_to_s3
      end
    end

    module S3BackgroundHandler
      extend ActiveSupport::Concern

      included do
        class << self


          def has_attached_file(name, options = {})
            super(name, options)

            all_options = ::Paperclip::Attachment.default_options.merge(options)
            process_in_background(name) if all_options[:process_in_background]
          end

          def process_in_background(name)
            original_options = {}
            save_to_disk = Proc.new{|name, attachment| send("#{name}_updated_at_changed?") && !attachment.uploading_to_s3?}

            before_save do
              attachment = send(name)
              if instance_exec(name, attachment, &save_to_disk)
                original_options = attachment.options.dup
                attachment.options.merge!({
                  path: LOCAL_PAPERCLIP_ATTACHMENT_PATH
                })
                attachment.extend ::Paperclip::Storage::Filesystem
              end
            end

            after_save do
              attachment = send(name)
              if instance_exec(name, attachment, &save_to_disk)
                queued_for_delete = attachment.instance_eval("@queued_for_delete")
                UploadDocumentToS3Job.perform_later(self.class.name, self.id, name.to_s, queued_for_delete)
                queued_for_delete.clear
                attachment.options.merge!(original_options)
              end
            end
          end

        end
      end

      LOCAL_PAPERCLIP_ATTACHMENT_PATH = ":rails_root/files/:class/:attachment/:id_partition/:style/:filename"

    end

  end
end

Paperclip::Attachment.include Extensions::Paperclip::Attachment
ApplicationRecord.include Extensions::Paperclip::S3BackgroundHandler


# Put this code in jobs directory
class UploadDocumentToS3Job < ApplicationJob
  queue_as :upload_document_to_s3

  def perform(class_name, id, attachment_name, queued_for_delete)
    record = class_name.constantize.find(id)
    attachment = record.send(attachment_name)

    # deleting
    s3_bucket = attachment.s3_bucket
    queued_for_delete.each do |path|
      begin
        attachment.send(:log, "deleting #{path}")
        s3_bucket.object(path.sub(%r{\A/}, "")).delete
      rescue Aws::Errors::ServiceError => e
        # Ignore this.
      end
    end

    # uploading
    original_options = attachment.options.dup
    attachment.options.merge!({
      path: ApplicationRecord::LOCAL_PAPERCLIP_ATTACHMENT_PATH
    })
    file_path = attachment.path
    attachment.options.merge!(original_options)

    File.open(file_path) do |file|
      attachment.uploading_to_s3 = true
      attachment.assign(file)
      attachment.reprocess!
      attachment.uploading_to_s3 = false
    end
    File.delete(file_path) rescue nil
  end

end

Assume we have the following code (We are using pundit
for authorization and Active model serializer
to format json response)

class User
  has_many :projects
end

class Project
end

class ProjectPolicy < ApplicationPolicy
  attr_accessor :user, :project

  def initialize(user, project)
    @user    = user
    @project = project
  end

  def show?
    user.member_of?(project)
  end

  def destroy?
    user.admin_of?(project)
  end
end

class ProjectsController

  def show
    authorize @project
    render json: @project
  end

  def destroy
    authorize @project
    @project.destroy
    head :no_content
  end
end

class ProjectSerializer
  attributes :name, :descroption  
end

When we request a project resource, we will get:

# http://myapp/projects/1

{
  "project": {
    "id": 1,
    "name": "My project",
    "description": "My project description"
  }
}

When a user tries to do any action on a project, we first authorize this user to make sure he can do this action on this project, everything seems fine.

But what about client side validation? If the mobile app or javascript code in the browser consuming this api wants to do client side validation for better user experience and to save the backend server from useless requests, then we have to return the policy with the json response like this.

class ProjectSerializer
  attributes :name, :descroption, :policy

  def policy
    project_policy = scope.policy(self.object)
    {
      show: project_policy.show?,
      destroy: project_policy.destroy?,
    }
  end
end

And in case you don’t already do this, add this line to application controller, such that we can use
methods available in rails html views (like current_user, which will be available within scope)

serialization_scope :view_context

# http://myapp/projects/1

{
  "project": {
    "id": 1,
    "name": "My project",
    "description": "My project description",
    "policy": {
      "show": true,
      "destroy": false
    }
  }
}

But then we have to remember that whenever we add a policy method to our policy class and use that method in our controller, we have then to add that method to the json response, so that the API consumer is aware of this policy.

The problem is that we may easily forget to do this, and new developers contributing to our code will most likely forget, as this is not an intuitive action to do, new developer must be told about it and they must remember it! A sign of a source of bugs.  

A simple solution I used is to use ruby metaprogramming to add the whole dependency thing to the API response, here is the black magic code (places in an initializer):

ActiveModel::Serializer.class_eval do
  def self.add_policies
    attribute :policy

    def policy
      policy_instance = scope.policy(self.object)
      policy_instance.as_json
    end
  end
end

And override as_json in ApplicationPolicy so that it returns only public methods ending with question mark (which indicates they are policy methods)

ApplicationPolicy
  def as_json
    policies = {}
    public_methods(false).select{ |method| method.to_s =~ /\?$/ }.each do |policy_method|
      can_perform_policy_method = send(policy_method)
      policies["#{policy_method.to_s.sub(/\?$/, '')}"] = can_perform_policy_method
    end
    policies   
  end
end

Then in ProjectSerializer, we just call add_policies

class ProjectSerializer
  add_policies
  attributes :name, :descroption  
end

And we have all our policy methods automatically added to to the project json object 🙂

سافرت إلى ألمانيا أربع مرات، قضيت ثلاث أسابيع في كل من المرتين الأولتين، و 6 أشهر في المرة الثالثة وأنا اﻵن في  المرة الرابعة. بداية انبهرت هناك بنظام الحياة الدقيق و المنظم، و أن كل ذي حق يأخذ حقه و نحو هذا، ولكن شيئا فشيئا يدرك المرء الحقيقة: أن حرص هؤلاء القوم على الحقوق و العدل، ليس حبا خالصا لهذه القيم أو عملا من أجلها، بل حرصا على الدنيا و تقاتلا عليها، و إفناء للعمر في سبيلها، في حياة مادية لا تطاق، لا تستطيع أن تطمع منهم في رحمة. فقوم لا تسيطر عليهم حقيقة أنه يوجد إله مطلع سميع بصير، و أنه هناك بعد الموت يوم يحاسب فيه الناس، و أن الأعمال الصالحة تثقل ميزانك يومها، و أن الفوز الحقيقي هو الجنة، قوم كهؤلاء لا يستطيع المرء أن يعيش معهم. حياة مادية يعمل المرء فيها كطاحونة في جو من السعار للدنيا، لا تجد قيم العطاء و الكرم و مكارم الأخلاق.. لا يفهمون معنى أن تداين الناس و لا تكسب من وراء إقراضك لهم. فهو لن يعود عليه شيئا إن أقرضك ثم عاد له المبلغ الذي أقرضه كما هو بدون زيادة. لا تجد للعفو عندهم معنى، و لا أن تكظم غيظك و أنت قادر على إنفاذه، لا معنى للدفع بالتي هي أحسن، و لا أن تتجاوز عن السيئة. لا حياة روحية هناك، يكبر الأب و الأم و يذهب بهم أبناؤهم إلى دور رعاية المسنين بدلا أن يُسكِنوهما معهم. مجتمع “بلاستيك” بلا سعادة على الإطلاق، يحاولون الحصول عليها في ملذاتهم الدنيوية كالخمر و النساء. لا يعون قوله تعالى :”المال والبنون زينة الحياة الدنيا والباقيات الصالحات خير عند ربك ثوابا وخير أملا” ، ” ادفع بالتي هي أحسن”، ” فمن عفا و أصلح فأجره على الله”. أذكر أنني جلست ذات مرة أنا و اثنين من زملائي مع دكتور في الجامعة الألمانية على مائدة عشاء في مصر-فرض هو نفسه علينا- و أخذ الرجل يتكلم عن أنه سعيد بالحياة في مصر، وأنه عندما يعود لألمانيا مؤقتا يتحرق شوقا للعودة إلى مصر و أخذ يشكو الحياة في ألمانيا بماديتها المفرطة وانعدام الروح فيها. لم أكن قد سافرت إلى ألمانيا وقتها فلم أستطع أن أتفهم كلامه تماما، ولكن بعد أن سافرت هناك أدركت صدق الرجل.

قد يقول قائل: ولكن لا يوجد في مصر أيضا هذه اﻷخلاق، فما الفرق بيننا وبينهم، أقول لك: هناك طائفة من المصريين لديهم نسبة عالية من هذه اﻷخلاق واﻹنسانية، وهذه الطائفة هي التي تجعل المرء يتحمل المعيشة في مصر، .. بخلاف أن المجتمع الذي يقرأ فيه القرآن يوجد عنده شيء لا يوجد في المجتمع الخالي من القرآن.. وهو ما لا يمكن التعبير عنه باللسان ولكن بالتجربة.

 

و قد وجدت أن الشهيد -بإذن الله- سيد قطب قد عبر ما أردت قوله في بيان لغوي رائع كعادته، فنقتبس صفحات من كتابه “نحو مجتمع إسلامي” :

أدري كيف يعيش الناس في أمريكا . بلد الإنتاج الفخم والثراء الفاحش واللذائذ المباحة . . لقد شهدتهم هنالك والقلق العصبي يأكل حياتهم على الرغم من كل مظاهر الثراء والنعمة ووسائل الراحة . إن متاعهم هياج عصبي ومرح حيواني وإنه يخيل اليك أنهم هاربون دائماً من أشباح تطاردهم ، إنهم الآت تتحرك في جنون وسرعة وهياج لا يقر له قرار . وكثيراً ما كان يخيل إلي أن الناس هناك في طاحونة دائرة لا تني ليل نهار ، صباح مساء ، تطحن بهم ويطحنون ، لا يهدأون لحظة . ولا يطمئنون إلى أنفسهم ولا إلى الحياة من حولهم – إن كانوا يحسون ما حولهم – ليست هنالك لحظة للتأمل ، ولا حتى للشعور بالحياة ذاتها وهي تدور حتى أوقات راحتهم ورياضهم في المنتزهات والغابات وعلى شواطيء الأنهار والبحيرات . . . تراهم فيها فنحس أنهم في ” شغل ؛ ” كأي شغل خلال العمل ، وكل ما هنالك من فارق أنهم في مكان غير المكان ، وفي عمل غير العمل . ولكن لا راحة ولا هدوء ولا تأمل ، ولا اطمئنان .

إنهم ينتجون كثيراً . ما في ذلك شك . إنهم يكسبون كثيراً ما في هذا شك أيضاً ولكن لمن ينتجون ولمن يكسبون ؟ لذات الكسب ولذات الانتاج ؛ العنصر الإنساني لا وجود له ، تأمل ذلك الكسب وذلك الانتاج الاحساس بدوافعه ونتائجه في يقظة فكر وحساسية قلب ، تذوقه بحس الإنسان المتميز عن حس الآلة . . كل ذلك لا تلمحه في سيما وجه ولا في تعبير لسان !

إنها الطاحونة الدائرة ليل نهار : تطحن ، وتبعثر ما تطحنه . وتجمعه مرة أخرى لتطحنه من جديد ! والناس والأشياء والزمان والمكان . . كلها تدور في تلك الطاحونة الدائرة التي لا تكل ولا تمل ، ولا تكف لحظة عن الدوران . .

إنه الدوار ! ! !

هدوء القلب . اطمئنان النفس . راحة الضمير . لذة الفرح اليقظ بثمرات الجهد والارتياح . المودات الحلوة بين الناس التجاوب الروحي بين الاصدقاء . الاهتمامات الناشئة عن الوشائج الوثيقة في الاسرة تلك المشاعر التي تشعر الفرد أنه ليس وحده . وتمنحه الثقة والطمأنينة والراحة بعد الجهد والكد والعناء العقيدة في قوة أكبر من قوة الأرض ، تلك العقيدة التي تشعر الفرد أنه ليس ذرة تائهة في هذا الكون العريض بلا أصل ولا قرار . . كل هذا لا وجود له في قاموس الحياة الأمريكية ، ولا في محيط النفس الأمريكية .

إنه الخواء ! ! !

الخواء على الرغم مما يبدو من زحمة في الحياة وامتلاء .

هنالك مرح كثير ، يخيل إلى من لا يعرف أنه سعادة . . . تلك الضحكات التي ترن في الهواء . تلك ” المهارشات ” التي تتحسس مساقط اللذة في الأجساد . تلك الكؤوس التي لا تفرغ من الخمر ، تلك الضجة التي لا تهدأ ولا تسكن . . ولكنه المرح الحيواني لا السعادة ، ولا الفرح ، إذ عربدة السكارى ليست سعادة ، كذلك المرح الحيواني ليس فرحاً ، إنه انطلاق الطاقة المكبوته تحت ضغط العمل المرهق . إنها قرقعة كقرقعة الآلات لتفريغ البخار . . .

ولكن أين الإنسان ؟ في كل هذا الركام ؟ أين الإنسان المتميز عن الآلة وعن الحيوان ؟ ولست اتصور من وراء الفلسفة المادية في روسيا إلا حياة أحط من تلك الحياة . فحتى ذلك المرح الحيواني الناشيء من الطلاقة والثراء في امريكا لا أتصوره هناك ؛ وفي هذا الدرك تستقر البشرية اليوم في الشرق وفي الغرب سواء .

إن البشرية كلها في حاجة الينا : في حاجة إلى عقيدة في الضمير ، يستروح في ظلها من هذا الهجير القائظ . ويطمئن في رحابها من ذلك القلق ، ويستقر في حضنها إلى قرار”.

و ختاما: اللهم اجعلنا هداة للإنسانية في بحثها عن حقيقة الحياة و الإنسان، و أن نخرجها من حيرتها و تخبطها إلى نور الإسلام و دفء الإيمان. اللهم آمين.

In some task today I had to use zigzag scanning on a grid rather than normal traversal , this is an illustration of this kind of scanning.

I thought of sharing the code I wrote so that anyone can use this ready-made one..I don’t claim it is the best nor the most elegant 🙂

C++ source code :


/**
 * traverses m*n grid in zigzag order
 */
void traverseZigZag(int m, int n) {

	int i = 0, j = 0, up=1;
	bool turned = false;
	int d[2][2] = { { 1, -1 }, { -1, 1 } };
	int corner[2][4] = { { 1, 0, 0, 1 }, { 0, 1, 1, 0 } };
	while (i < m && j < n) {
		//here you have your (i,j), do what you want with them.
        printf("%d %d\n",i,j);
		if (i == 0 || j == 0 || i == m - 1 || j == n - 1) {
			if (!turned) {
				int k = 2 * (up * (j / (n - 1)) | (1 - up) * (i / (m - 1)));
				i += corner[up][k];
				j += corner[up][k + 1];
				turned = true;
				up = 1 - up;
				continue;
			} else
				turned = false;
		}
		i += d[up][0];
		j += d[up][1];
	}
}