Difference between string and symbol in ruby

Ruby symbol and string does the same thing except symbol is more efficient in terms of memory and time.

As explained here

Symbol is the most basic Ruby object you can create. It’s just a name and an internal ID. Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.

ruby string symbol

Therefore, when do we use a string versus a symbol?

  • If the contents (the sequence of characters) of the object are important, use a string
  • If the identity of the object is important, use a symbol.

We can change them to each other like this

puts “string”.to_sym.class # Symbol

puts :symbol.to_s.class    # String

Symbols are particularly useful when creating hashes and you want to have a distinction between keys and values.

Rails migrations best practices

Avoid using Rails models in migration.

Reasons:

  1. Models might have some lifecycle callbacks which we dont want to be invoked in a migration.
  2. As we know what we are doing we dont want to deal with validations.
  3. Model names can change irrespective of db table.
  4. Try to use raw sql as close as possible.

Squash them after a period of time.

Reasons:

  1.  To my experience over a period of time these migration files are painful and useless.
  2. Every rake db:migrate might take a few seconds, or creating of a new database might take a few minutes when these files are big. Consider using tools like squasher.

Make them irreversible.

Reason:

In Production it makes sense to have IrreversibleMigration as the code is tested in lower environments. If there is an issue try to fix it with a follow up migration.

Note: If there is a new developer in your team and setting up their environment. Let them do `rake db:schema:load` to get latest db copy.

Rails after_validation or before_save

I dont think i used after_validation ever as before_save(or similar callbacks like before_create or update) is the one which fits. Usually the flow is

Screen Shot 2018-08-03 at 1.45.57 PM

before_save seems to be the last step in the process and by the time it reaches there the record is valid. Like you wanted it to happen every time when validation is successful.

after_validation is called irrespective of the validation failed or not. I cant think of a scenario where you want to use it.

We cannot substitute after_validation for before_save as we can not guarantee that the record is always going to be valid.

ActiveRecord::EagerLoadPolymorphicError: Cannot eagerly load the polymorphic association

 

If you have encountered this error and wondering how to fix it this post is for you.

Rails raises this error when it tries to eager load a polymorphic association using a JOIN.

For example i have a Booking which belongs_to polymorphic association order. An Order can be a PickupOrder or DeliveryOrder

class Booking < ApplicationRecord
  belongs_to :order, polymorphic: true
end
class PickupOrder < ApplicationRecord
  has_many :bookings, as: :order, dependent: :destroy, inverse_of: :order
end
class DeliveryOrder < ApplicationRecord
  has_many :bookings, as: :order, dependent: :destroy, inverse_of: :order
end

I can load all bookings along with orders like this

Booking.includes(:order)

Now if I want to search list of bookings by `order_name` like `ja`

Booking.includes(:order).references(:order).where("order.order_name ilike %ja%")

Throws the error

​​ActiveRecord::EagerLoadPolymorphicError: Cannot eagerly load the polymorphic association :order

Solution: Do it in sql. with left outer joins.

Booking.joins("left outer join delivery_orders on delivery_orders.id = bookings.order_id and bookings.order_type='DeliveryOrder'").
        joins("left outer join pickup_orders on pickup_orders.id = bookings.order_id and bookings.order_type='PickupOrder'").
        where("pickup_orders.order_name like '%ja%' or delivery_orders.order_name like '%ja%'")

Happy coding!

jsoapi-resources belongs_to not implemented?

Have you ever encountered this error while working on jsoapi-resources ?

`DEPRECATION WARNING: In XXX class you exposed a `has_one` relationship using the `belongs_to` class method. We think `has_one` is more appropriate. If you know what you’re doing, and don’t want to see this warning again, override the `belongs_to` class method on your resource.

If yes this post is for you. Dont break your heads its on `​jsonapi-resources`.

It looks like jsoapi-resources did not implement the `​belongs_to` as how it should be. At least as of this writing (0.9.0v). It treats `belongs_to` and `has_one` relations in the way. here is the source which points to this. So for time being change your `belongs_to` to `has_one` and you are gold. Happy coding!

Reasons to hate action cable

Hi all recently we got a task to integrate with a 3rd party api, get data and display on our site. It is taking 5-10 secs to get response from it. We went on trying ActionCable first as our backend is rails thinking that it gets us running without much integration hassle.

We ended up having bad experience with it. My recommendation is to not to go for ActionCable at any case. Rails community included this in Rails 5 but the client library is poorly written. As per this writing the Rails 5.2 also doesn’t have any updates to ActionCable.

Main Reasons:

  • Annoying Reconnections: ActionCable has this class called Connection which is used for authentication and establishing a connection. The client library has a connection monitoring pool which runs for every 3 secs.  There is no way to know why the server rejects the connection as it returns 1006(forceful disconnect). Still  the client continuously tries to establish the same connection again and again which is frustrating.
  • Not flexible: We look into ActionCable as a solution for websockets. Its just an option if you are using traditional Rails application (though it doesnt scale). It is so tightly coupled that we cant use it with any other websocket client library.

We ended up using Pusher which i discussed in this post.