Best smooth horizontal JS you’ll ever find

If you ever find yourself in a situation where you’ll need a smooth horizontal scroll for both, a good old mousewheel and a trackpad (iPad, MacBook etc.), there is a good plugin, called ‚mousewheel‘.

It’s setup, however, can be rather tricky. I ended up a few times having my scroll items bounce wildly around, stutter or jump on initial hit.

The piece of code you’ll find upon hitting this link solves all of those problems in just one line of code!

Happy JS’ing!

Ruby on Rails – Using Tags as Model field

If you have a separate model for a Tag and manage them separately, it is pretty easy to attach those tags to another model via a field „tags_ids“. But, let’s say, you’ve got some SEO-settings for a object. It wouldn’t make much sense to store tags in a separate model for all your other pages.

To store tags as a property of any given object we will utilise PostgreSQL’s ability to have an array as data type. So, first of all, I don’t want to add all SEO-fields to every other object over and over again. Let’s create a separate SEO-model:

class CreateSeos < ActiveRecord::Migration[5.1]
  def change
    create_table :seos do |t|
      t.string :title
      t.text :description
      t.string :image


Then add the keyword column:

class AddKeywordsToSeos < ActiveRecord::Migration[5.1]
  def change
    add_column :seos, :keywords, :string, array: true, default: []

Add references to appropriate other tables:

class AddReferencesToSeos < ActiveRecord::Migration[5.1]
  def change
    add_reference :seos, :post, foreign_key: true
    add_reference :seos, :product, foreign_key: true

For front-end editing I’m using bootstrap-tagsinput (here is an example). Install it via yarn add bootstrap-tagsinput(or download files manually). Don’t forget to include JS aswell as CSS files.

On the front-end part it is important to use a select field instead of simple text_field to be able to select multiple tags. Here is my full html code for the seo block:

    =f.fields_for :seo do |seo_builder|
          =seo_builder.text_field :title, class: 'form-control'

          =seo_builder.text_area :description, class: 'form-control', rows: 4

 :keywords, {|i| [i, i]}, {}, {id: 'object_keywords', class: 'form-control custom-bootstrap-tagsinput', data: {role: "tagsinput"}, multiple: true}

For the backend part include seo to your corresponding models:

class Post < ApplicationRecord

  has_one :seo
  accepts_nested_attributes_for :seo, allow_destroy: true


In your controller, whitelist the attributes (important to use keywords: [] to indicate an array) and don’t forget to build the fields if they aren’t present yet.

seo_attributes: [:id, :title, :description, :image, keywords: []]
def new
  @post =
  if @post.seo.blank?
  @tags = @post.seo.keywords || ""

def edit
  if @post.seo.blank?
  @tags = @post.seo.keywords || ""

Now you can enjoy setting any variable tags and them being persistent in your database. Happy coding!


Rails bulk delete items on frontend part

So when your database grows it might come in handy if you give your customers the option to bulk manipulate data in lists. I’ve got a list of products and my client told me, that they often create dozens of test items to check out things and then they delete them. Clicking one by one and, especially, waiting every time for the page to load can be tiresome. Here is my approach:

Wrap the listing table in a form

=form_tag admin_bulk_delete_path(sublevel: params[:sublevel], :id => "bulk-edit-form") do
          =hidden_field_tag :object, object_name(object)
                  -if object.has_attribute? :url
                -object.each do |obj|
                      =check_box_tag "object_ids[]",, false, class: "i-checks bulk_actionable"
                    -if obj.respond_to?(:url)
                        =link_to t('admin.form.actions.edit.verb'), send("edit_admin_#{local_assigns[:namespace]}#{object_name(object)}_path", obj), class: "btn-white btn btn-xs", id: "edit_list_item_#{}"
                        =link_to t('admin.form.actions.delete'), send("admin_#{local_assigns[:namespace]}#{object_name(object)}_path", obj), method: :delete, data: {confirm: t('admin.form.confirm.main') }, class: "btn-white btn btn-xs", id: "delete_list_item_#{}"
                  = submit_tag t('admin.form.actions.bulk_destroy'), class: "btn btn-xs btn-danger", id: "bulk-delete", data: {confirm: t('admin.form.confirm.bulk_delete')}

Don’t get confused by my ‚object’… err… object, it serves the purpose of enabling many models to use this listing partial. The main parts are ‚form_for‘, the checkbox and the ’submit_tag‘. It is important to use an array for storing the checkbox values, or else we won’t be able to retrieve all id’s at once.

Now the form leads us to the custom controller (‚rails g controller bulk_actions‘):

class Admin::BulkActionsController < AdminController

  def bulk_delete
    object = params[:object]
    if params[:object_ids].is_a?(Array) && params[:object_ids].length > 1  #let's make sure we got what we expected
      @objects = object.singularize.capitalize.constantize.find(params[:object_ids])
      @objects.each do |object|
      flash[:success] = t('admin.flash.success.delete')
      redirect_to send("admin_#{object.pluralize}_path", sublevel: params[:sublevel])
      flash[:danger] = t('')
      redirect_to send("admin_#{object.pluralize}_path", sublevel: params[:sublevel])

First of all, I’m getting the object from ‚params[:object]‘ (this is why I included the hidden_field_tag in my form). Since I’m using the partial for any model, I need to know, do I delete the Post model or the Product model right now. The if-clause makes sure we only handle a bunch of items, it does not make any sense to bulk delete 1 item. Since my object is rather a string, I need to convert it to a modal constant. Then we simply iterate over each found object and destroy it. You can disregard the ’sublevel‘ part.

Now for the frontend – I wanted the delete button only to appear if two or more items are selected and be hidden elsewise. Since I’m using iChech checkboxes we need to hook up on different methods. Particularly it is ‚ifToggled‘ in this case:

  $('input').on('ifToggled', function(event){
      var check_count = $('input:checked').length;  //count the number of checked elements
      if( check_count > 1 ) {
      } else {

Add one last thing – the route

post 'bulk_delete', to: 'bulk_actions#bulk_delete'

And you are ready to go!

Heavily inspired by this article.

Project Showcase: Uzhin Doma

I am happy to announce, that my first „serious“ project for an already established project finally been released. It is a Russian service for food ingredients delivery, ‚Uzhin Doma‘ (roughly translated as dinner at home). You don’t receive a precooked meal, but rather a list of ingredients, exactly measured for each dish and you can cook it yourself.

So, basically, you save time twice – you don’t need to buy ingredients yourself and you don’t have to think about what to cook every day. You just lean back, relax, follow the instructions and receive an extraordinary result.

What about Rails?

Enough small talk, let’s get down to business. Some of this project’s interesting features are:

  • custom design (thanks to @bender)
  • custom front-end (thanks to @antiquar)
  • full integration with Russian CRM Bitrix
  • delayed_job integration
  • SMS verification upon login (everything via AJAX)
  • checking for a valid promo code on creating a new order
  • a lot of AJAX overall 🙂
  • Cloudpayments integration for credit card processing

Bitrix API Integration

Since this is a heavy topic, I decided to dedicate a complete description to it. Integration with Bitrix provides few things:

  • searching for user based on phone number
  • if user is found, a new deal is created
  • if no user is found, a new lead is created
  • to each deal/lead are added bitrix-internal products which are based on site’s internal products
  • if credit card is processed correctly, Bitrix is updated accordingly
  • on profile page all old orders from Bitrix are wired up (once. After that we only query the internal page’s orders to reduce the load)

Enjoy the screenshots:

Select your dinner options there

SSL for Ruby on Rails app

When pummeling around this problem I figured out there are not many step-by-step tutorials for dummies (like me). So after fixing all issues, I think it’s good practice to share the knowledge.

How to set up SSL for your rails application

Step 1: Obtain the SSL certificate. Various providers offer them. A certificate is, simply put, a bunch of text. It is divided into few parts. Usually two or four. The first one is the key. The second one is the actual certificate. It might be split into three separate files.

Step 2: Place those files on your server. I put them inside the Nginx directory (/etc/nginx/ssl/project_name/certificate.crt – for the certificate and /etc/nginx/ssl/project_name/certificate.key – for the key) Be sure, to concatenate your certificate the right way. If it’s not concatenated yet, take care of combining them together with, the right way – there is always a middle part, a prefix, and a suffix part. Putting middle part at the end will cause the file to malfunction.

Example of the certificate file

Step 3: Configure Nginx. My example is listed below. It shows how you can run both versions, http and https at the same time. Additionally, I included a redirect, so my client doesn’t need to buy certificates for each similar domain.

upstream puma_project_name {
  server unix:///home/deploy/apps/project_name/shared/tmp/sockets/project_name-puma.sock;

server {
  rewrite ^$request_uri? permanent;

server {
  listen 80;

  root /home/deploy/apps/project_name/current/public;
  access_log /home/deploy/apps/project_name/current/log/nginx.access.log;
  error_log /home/deploy/apps/project_name/current/log/nginx.error.log info;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;

  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://puma_project_name;

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;

server { 
  listen 443 ssl;

  ssl_prefer_server_ciphers On;

  ssl_certificate /etc/nginx/ssl/project_name/certificate.crt; 
  ssl_certificate_key /etc/nginx/ssl/project_name/certificate.key; 
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  root /home/deploy/apps/project_name/current/public;
  access_log /home/deploy/apps/project_name/current/log/nginx.access.log;
  error_log /home/deploy/apps/project_name/current/log/nginx.error.log info;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;

I’m almost sure that this is the most basic and ineffective approach, but it’s working quite well.

YCMS – first development friendly CMS on Ruby on Rails

Always wanted to bootstrap your application really fast, but considering ActiveAdmin or RailsAdmin was a pain because of their limited flexibility? Now, with YCMS you don’t need to worry anymore. This CMS is as simple as it could ever be. No mountable Engines, not gems, simply git clone this application, rename your databases and you are set up and ready to go. My ruby on rails cms is customizable just as every normal app you would write from scratch. There is no hidden DSL, special methods or other stuff. You need a new model, you simply add it as you would to your own application.


  • Already included models for: posts, pages, page/post-categories, users
  • User management via Devise gem
  • Base settings available
  • Assets, views, controllers are split up into front and admin part.
  • Heavily DRY – all common CRUD methods are managed via a controller concern. There is only one form for each model, still perfectly clear and manageable via partials
  • Supported internationalization from the box
  • Controller, model and feature tests.
  • For I18n tests I am using i18n-task gem
  • Human readable routes

Please check it out on GitHub –

Fork, contribute, enjoy!

Create a search…then speed it up by a factor of 50!

One great way to implement a basic search is to put all your data fields into one big array and then perform the search on this one field. Let’s say, you’ve got a Customer model. Open up customer.rb (in app/models/) and write this few lines of code:

class Blueprint < ActiveRecord::Base
 scope :search, ->(search){ where('keywords LIKE ?', "%#{search.downcase}%") }

 before_save :set_keywords

 def set_keywords
    self.keywords = [name, email, birthdate, etc.].map(&:downcase).join(' ')

To pick only the searched items we’re creating a scope to which we’re passing the search argument. You can add a function, which will turn all separate fields into one big keywords array.

Now, open up your Controller (CustomersController.rb)

class CustomersController < ApplicationController
  @customers =[:search])

If desired, you can add some validation for cases if no search parameter is provided.

This approach won’t yield you amazon like results, but can bring one pretty far.

Step up the game

If you want to make one little step further and do not want to bother with „heavy industry“ tools like ElasticSearch, then you can utilize PostgreSQL’s awesome built in indexing features. This approach requires a bit more setup, than the first one, but once you follow those steps, it will appear straight forward.

The main goal is to write our custom SQL query. In the end what we want to achieve is something like this:

  lower(first_name) LIKE 'bob%' OR
  lower(last_name)  LIKE 'bob%' OR
  lower(email)      LIKE ''
  email = '' DESC,
  last_name ASC

Using rails syntax this would mean we need a query like this:

Customer.where("lower(first_name) LIKE :first_name OR " +
  "lower(last_name) LIKE :last_name OR " +
  "lower(email) = :email", {
    first_name: "bob%",
    last_name:  "bob%",
    email: ""
}).order("email = '' desc, last_name asc")

To create this query and keep things clean I’m using an extra class (models/customer_search_term.rb):

class CustomerSearchTerm
  attr_reader :where_clause, :where_args, :order
  def initialize(search_term)
    search_term - search_term.downcase
    @where_clause = ""
    @where_args = {}
    if search_term =~ /@/

#Following code goes there

Now we need this helper function, „build_for_name_search“ (I’ll omit the first one for now).

def build_for_name_search(search_term)
	@where_clause << case_insensitive_search(:first_name)
	@where_args[:first_name] = starts_with(search_term)

	@where_clause << " OR #{case_insensitive_search(:last_name)}"
	@where_args[:last_name] = starts_with(search_term)

	@order = "last_name asc"

def starts_with(search_term)
	search_term + "%"

def case_insensitive_search(field_name)
	"lower(#{field_name}) like :#{field_name}"

This function does nothing else rather than building the string for our SQL query. You can verify it by examining the variables – @where_clause is a string, while @where_args is a hash.

Finally, let’s build our controller:

class CustomersController < ApplicationController
	def index
		if params[:keywords].present?
			@keywords = params[:keywords]
			customer_search_term =
			@customers = Customer.where(
			@customers = []

We’re almost there. This search works, but it’s still a bit slow (see below for speed results).

Now we need to create custom indexes on those tables. We will stick to old up and down migration methods, since rails won’t understand our custom SQL migration if we’d stick to „change“.

class AddLowerIndexesToCustomers < ActiveRecord::Migration
  def up
  	execute %{
  			customers (lower(last_name) varchar_pattern_ops)

  	execute %{
  			customers (lower(first_name) varchar_pattern_ops)

  	execute %{
  			customers (lower(email))

  def down
  	remove_index :customers, name: 'customers_lower_last_name'
  	remove_index :customers, name: 'customers_lower_first_name'
  	remove_index :customers, name: 'customers_lower_email'

It’s important to use „varchar_pattern_ops“, since we are not using an exact match, but instead using a like operator. Now, if we fire up rails dbconsole and perform EXPLAIN ANALYZE on both methods, we can see the difference.Ama

This was the original result:

Started GET "/customers?utf8=%E2%9C%93&" for ::1 at 2017-01-04 22:19:21 +0300
Processing by CustomersController#index as HTML
  Parameters: {"utf8"=>"✓", "keywords"=>"", "commit"=>"Find Customers"}
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  Customer Load (561.3ms)  SELECT "customers".* FROM "customers" WHERE (lower(first_name) like 'andres%' OR lower(last_name) like 'andres%' OR lower(email) like '')  ORDER BY lower(email) = '' desc, last_name asc
  Rendered customers/index.html.haml within layouts/application (572.4ms)
Completed 200 OK in 591ms (Views: 27.8ms | ActiveRecord: 561.6ms)

After spicing things up:

Started GET "/customers?utf8=%E2%9C%93&" for ::1 at 2017-01-04 22:40:59 +0300
Processing by CustomersController#index as HTML
  Parameters: {"utf8"=>"✓", "keywords"=>"", "commit"=>"Find Customers"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  Customer Load (2.1ms)  SELECT "customers".* FROM "customers" WHERE (lower(first_name) like 'andres%' OR lower(last_name) like 'andres%' OR lower(email) like '')  ORDER BY lower(email) = '' desc, last_name asc
  Rendered customers/index.html.haml within layouts/application (12.7ms)
Completed 200 OK in 32ms (Views: 28.3ms | ActiveRecord: 2.3ms)

This is an increase by a factor of 243!

Create reusable form partials in Rails

If you’ve got an admin part in your rails app and some settings to take care of, chances are that you have a lot of similar data. And what can be more wearying, than creating all those forms, index/edit/new views over and over again? Of course you could use the scaffold, but I personally strongly dislike it.

So I figured out I try to make my partials variable as possible. This post shows you how you can create highly reusable form partials.

My structure is as following:

There is an admin panel. Inside admin panel there are settings (which get repetitive) and inside settings you can manage models like „colors“, „patterns“, „fabric“ (you can guess it – it’s a clothing online shop). All of them contain identical data, but have some differences as well.

I’ve got only 3 views – index, edit and new, because there is no sense for having a show view, as it should be the edit view right from the get go. This said, we need only two partials – one, for listing items inside our index view and one for creating and editing existing data.

Let’s start with routes.rb:

namespace :admin do
  	get '', to: 'dashboard#index', as: "/"

  	namespace :settings do
  		resources :borders
  		resources :colors
  		resources :patterns
  		resources :categories
      resources :fabrics

Simple dashboard when you visit plain old „/admin“ and then resources inside another namespace „settings“.

My index view – index.html.haml:

=render partial: 'admin/shared/list_items', locals: {name_ru: 'ткань', current_objects: @fabrics, name_en: "fabric"}

As you can see, I pass 3 local variable to my partial (this is the only thing you need to edit for each model. But hey, it’s only 3 words!) – the russian name, so I can have some customized buttons and links. The current collection and the name in english.

Listing items partial (a.k.a. index)

            %th.text-center Select
            %th Наименование
            %th.text-right Статус
          -unless current_objects.nil?
            -current_objects.each do |object|
                    %input{:name => "mobileos", :type => "checkbox", :value => "FR"}
                  =link_to, send("edit_admin_settings_#{single}_path", object)
                    %button.btn.btn-success.br2.btn-xs.fs12.dropdown-toggle{"aria-expanded" => "false", "data-toggle" => "dropdown", :type => "button"}
                    %ul.dropdown-menu{:role => "menu"}
                        =link_to 'Редактировать', send("edit_admin_settings_#{single}_path", object)
                        =link_to 'Удалить', send("admin_settings_#{single}_path",, method: :delete, data: {confirm: 'Действительно удалить?'}
                =link_to "Новая/ый #{name}", send("new_admin_settings_#{single}_path"), class: 'btn btn-primary'

Well, apart from some html, the important things are:

  • to check if there is at least one item in the collection (remember, we pass the collection under the name „current_objects“)
  • for each object in current_objects we access it using the variable „object“
  • since our partial is variable we can’t use hardcoded paths, like „admin_settings_colors_path“. Meaning we must make use of the „send“ method, which basically makes a method from a string. To pass parameters to a method created by „send“ you simply put this parameter as a parameter to the send-method. send(„hello_there“, caramba) is equivalent to calling method hello_there(caramba)
  • Because „object“ is actually an object (wow!) we can’t use it in the path generation. This is why I pass „single“ as a local variable. „Single“ is simply the singular form of the model (category, color, pattern etc.)

My edit/new view:

They are absolutely identical.

  =render 'admin/navigation/flash'
  =render partial: 'admin/shared/form', locals: {current_object: @pattern}

I render some flash messages to tell users about successful or failed actions. Then I render my second partial using again a local variable to transmit the collection.

Form partial

The core 🙂

=form_for [:admin, :settings, current_objects] do |f|
      %span.panel-title.hidden-xs Добавить новую сущность
          %a{"data-toggle" => "tab", :href => "#tab1_1"} Описание сущности
          -if current_objects.respond_to?(:picture)

              .fileupload.fileupload-new.admin-form{"data-provides" => "fileupload"}
                  -unless current_objects.picture.nil?
                    =image_tag current_objects.picture
                    %img{:alt => "holder", "data-src" => "holder.js/100%x140"}
          {:name => "name2", :placeholder => "Img Keywords", :type => "text"}
                      %label.field-icon{:for => "name2"}
                      %span.fileupload-new Select
                      %span.fileupload-exists Change
                      =f.file_field :picture, id: 'fileupload', type: :file
                      / %input{:type => "file", name: 'picture'}
              %label.field.prepend-icon{:for => "name2"}
                =f.text_field :name, id: "price", class: "event-name gui-input br-light light", placeholder: 'Название сущности'
                %label.field-icon{:for => "name2"}
            -if current_objects.respond_to?(:price)
                  =f.number_field :price, id: "price", class: "event-name gui-input br-light light", placeholder: 'Стоимость'
                  %label.field-icon{:for => "comment"}
                    %strong> Hint:
                    Don't be negative or off topic! just be awesome...
            -if current_objects.respond_to?(:hex)
                  =f.text_field :hex, id: "hex", class: "event-name gui-input br-light light", placeholder: 'Hex-значение цвета'
                  %label.field-icon{:for => "comment"}

        / end section row section
                %input{:checked => "", :name => "info", :type => "checkbox"}
                  Save Customer
                  %em.small-text.text-muted - A Random Unique ID will be generated
                =f.submit "Сохранить", class: "btn btn-primary"
          / end section
  -if current_objects.respond_to?(:image)
        %span.panel-title Загруженные фотографии рецепта
 фото можно удалить
        =f.fields_for :pictures do |builder|
          =image_tag builder.object.image.mini_thumb.url, class: "img-responsive thumbnail mr25 uzhin_doma_mini_thumb"
          =builder.label :_destroy, 'Удалить фотографию?'
          =builder.check_box :_destroy

Well, again a lot of HTML, but I will summarize the core points for you:

  • First of all we build our form using triple nesting =form_for [:admin, :settings, current_objects] do |f|
  • Now comes the most interesting part – surely your models will differ a bit. Maybe on has images to upload, the other doesn’t. One has a price tag, other don’t. Etc. and so on. Thus, we need to create an all-purpose-form, disabling fields when not required. This is done by respond_to? method. You can see it in this line  -if current_objects.respond_to?(:picture) This basically means, that if there is no :picture method for current object, the block below won’t be executed. Nifty, eh?
  • In my example every model has a field, called „name“, this is why I don’t check for it. All other fields are encapsulated in a respond_to? check.


With just a few methods – send and respond_to? you can create highly reusable partials where your maintain effort goes towards zero. Only one file for each action (index and edit/new) – truly amazing!

Bitrix 24 REST API

It is quite possible, that none of my visitors will ever stumble upon the Russian CRM system called Bitrix, however if you are one among the unluckiest people, this article might be useful for you. More specific, I will cover how to work with the cloud solution, Bitrix24 and its REST API. There is almost no clear documentation, thus, I think a complete resource might come in handy some time.

Getting started

So what exactly will we be doing? We will connect a web application to an existing bitrix24 portal. Possible use cases are:

  • Upon registration on your web application you want to create a lead inside the CRM
  • Upon completing an order you want to create an order inside the CRM
  • etc.

First and foremost you need to register yourself as a developer at bitrix24 marketplace, there are a lot of links leading to different sub-pages of, you’ll need this one: Don’t worry, you won’t need to fill out papers as required for a partner account. Just a regular one will do, I think it’s called a ‚technological partner‘.

Create your app

Next step is to create your app on marketplace. I don’t like calling it an app, because it collides with our web app, so let’s call it a container for our web application. When logged in as a technical partner, visit this page:

There you can register a container. Detailed on screenshot –

  1. Is my status (technical partner)
  2. Menu, where you can find the required link
  3. The actual button you need to press to create a new container

Check all those checkboxes –

After creation you can click on your app container (most likely you’ll have just this one – recently created – in the list) and then you should see something like this:

client_id and client_secret is what’s important.


Do not forget to create at least one version! There you can type in a url for callbacks, it’s important for proper functioning aswell. Check out the screenshot:

Managing bitrix24

Now comes the tricky part – we need to authorize your web app inside the bitrix24 portal. To do so you need to contact the administrator of bitrix portal.

If you are yourself an admin it gets a bit easier. Just visit „add an app“ – and click on „for personal usage“.

Check „API use only“ and at least CRM in the long options list. In the marked field we need to provide the url we typed in in the versions tab at marketplace website (

After adding your app container to your Bitrix24 portal you’ll obtain new client_id and client_secret, just like here – Only use them from now on! You won’t need any tokens from marketplace.

Last part is to obtain refresh and access tokens. This might be quite cumbersome due to the fact, that you’ll need to retrieve a „code“ parameter which lives only 30 seconds. It’s not a big deal if you use some written program for all this stuff, but you can do it by hand as well.

Now open two tabs. Type in the first one (don’t hit enter yet!) –<ENTER CLIENT ID FROM BITRIX PORTAL HERE>&redirect_uri=<ENTER URL FROM MARKETPLACE PAGE>

Type in the second one (don’t hit enter yet!) –<CLIENT ID FROM BITRIX PORTAL>&client_secret=<CLIENT SECRET FROM BITRIX PORTAL>&redirect_uri=<ENTER URL FROM MARKETPLACE HERE>&scope=<your-scope>&code=<LEAVE EMPTY AS OF NOW>

Input every variable without <>. Now hit enter in the first tab. You will be redirected to another URL where there will be a code parameter (with a value). Copy that value and insert it in the corresponding place in the second tab. Hit enter again. Now you should receive the desired tokens. Keep them safe!


Refresh token is valid for about a month. It is wise to store it in your database with a separate created_at date point. Upon expiring hit the url
    &client_id=<CLIENT ID>
    &client_secret=<CLIENT SECRET>
    &refresh_token=<CURRENT REFRESH TOKEN>

You will receive a new refresh token. Answer will look like this:

GET /oauth/token/

HTTP/1.1 200 OK
Content-Type: application/json

    "access_token": "ydtj8pho532wydb5ixk78ol7uqlb7sch",  
    "client_endpoint": "",  
    "domain": "",  
    "expires_in": 3600,  
    "member_id": "a223c6b3710f85df22e9377d6c4f7553",  
    "refresh_token": "3s6lr4kr3cv2od4v853gvrchb875bwxb",  
    "scope": "app",  
    "server_endpoint": "",  
    "status": "T"

Same process goes for access token, with the only difference that it expires every hour. So you should check if the creation date was larger than 3600 seconds, and if yes, call the same url. You can separate those two refresh methods or call them all at once and update both tokens every time.

The fun part

Now you surely want to interact with the data from your Bitrix24 portal, right? You’ve made all the way down for this one reason. There are several methods (I will be covering only the CRM part, no calendar etc.).

The general url is following: https://<YOUR BITRIX PORTAL><METHOD NAME>.<TRANSPORT TYPE>&auth=access_token&<PARAMETERS>


Get all leads

Post a new lead

Please be careful as there are no quotation marks allowed. If there are whitespaces inside your data, make sure to use %20 instead. If you are using cyrillic data, make sure to encode it to stuff like this: %D0B3%D1B10 (in rails I do it by using URI.escape – encoded_name = URI.escape(name) )

Post a new deal

Searching (and filtering)
&auth=<YOUR TOKEN HERE>&filter[PHONE]=8903227

Please note, that the filter method only searches from the left side, i.e. if the number in the Bitrix 24 portal is as following: 8 903 227 88 74 and you search for 8874 you won’t find anything. You need to start from the left, meaning searching either 8903 or 8903227 or even the full number. It also matter how the phone number is stored inside Bitrix (that’s some crazy bullsh*t, I tell you), because you need to check for all number formats,

8 903 227 88 74
8 903 227-88-74

Are all different numbers for the filter method.

Last, but not least you can specify the output with „select“ chaining. In my example I’m grabbing ID, Name and Last_Name from all possible fields.

Everything else

It is highly recommended to create a new portal for testing, then install the documentation app. It has a console built in where your can look up all the remaining methods and url calls. Simply hit the „run this code“, then click on the „post“ tab –

Scroll down. There you should thee the complete url from the example –


Working with Bitrix24 REST API is far away from being easy like working with Twitter or Instagram API. However you can still do it. I hope my guide will help one lost soul out there. I’m planning on writing a gem for Ruby on Rails which will do all the ugly work for you. It should be out on the githubs around winter 2016/2017.

AbsoluteAdmin vs. method: :delete

Hey folks, I recently stumbled upon an issue, which caused my destroy links to malfunction. It’s bundled to using AbsoluteAdmin ( I’ve separated everything in my project into two folders – admin and front (for admin part I’m using AbsoluteAdmin and for the front part another theme). This is my loading order for admin.js (assets/javascripts/admin) :

//= require_tree ../../../vendor/assets/javascripts/admin/plugins/moment/.

//= require jquery
//= require jquery_ujs

//= require_tree ../../../vendor/assets/javascripts/admin/jquery_ui/.
//= require_tree ../../../vendor/assets/javascripts/admin/plugins/.
//= require_tree ../../../vendor/assets/javascripts/admin/daterange/.
//= require_tree ../../../vendor/assets/javascripts/admin/utility/.

//= require_tree ../../../vendor/assets/javascripts/admin/demo/.

//= require admin/main

//= require_self
//= require_tree ../../../app/assets/javascripts/admin/.

//= require turbolinks

I’ve spent a lot of time figuring out how to make all of those JS from AbsoluteAdmin work, thus, I think, this exact order is important. However, admin/main (which is located at vendor/javascripts/admin/main.js) apparently breaks UJS. After a bit of detective work there was only one candidate for this behavior – the function ‚runHeader();‘

return {
      init: function(options) {

         // Set Default Options
         var defaults = {
            sbl: "sb-l-o", // sidebar left open onload 
            sbr: "sb-r-c", // sidebar right closed onload
            sbState: "save", //Enable localstorage for sidebar states

            collapse: "sb-l-m", // sidebar left collapse style
            siblingRope: true
            // Setting this true will reopen the left sidebar
            // when the right sidebar is closed

         // Extend Default Options.
         var options = $.extend({}, defaults, options);

         // Call Core Functions
         // As of 28/08/2016 runHeader causes jquery_ujs to break
         // runHeader();


As you can see, I commented it already out (line 22 in the snippet and line 720 in the actual file) and now everything works as expected!