Monday, September 04, 2017

Rails 5 makes belongs_to association required by default


In Rails 5, whenever we define a belongs_to association, it is required to have the associated record present by default. This change will have some impact if you are migrating an existing Rails 4 application in to Rails 5 and foreign key is not mandatory in your application. It will trigger validation error if associated record is not present.

For example, if your User model has city_id as foreign key, then if you create user without adding city_id then rails 5 will throw validation error.



class User < ApplicationRecord
  belongs_to :city
end


How to achieve this behavior before Rails 5

In Rails 4.x world in order to add validation on belongs_to association, we need to add option required: true.  By default is false


class User < ApplicationRecord
  belongs_to :city, required: true
end


Turn off this default behavior in Rails 5

If we want to turn off this behavior we can use :optional => true . When set to true, the association will not have its presence validated.


class User < ApplicationRecord
  belongs_to :city, optional: true
end

You can turn off this in entire application by setting


Rails.application.config.active_record.belongs_to_required_by_default = false

Thursday, August 17, 2017

Rails 5: Autoloading and Reloading Constants



Rails 5 disables autoloading after booting the app in production. With Rails 5, autoloading is now completely disabled if config.eager_load = true.

The concept of loading all the constants even before they are actually needed is called “Eager loading”. In a way it is opposite of “Autoloading”. In the case of “Autoloading” the application does not load the constant until it is needed. Once a class is needed and it is missing then the application starts looking in “autoloading paths” to load the missing class.

When application boots in production then the application loads all constants found in all directories listed in eager_load_paths. If folder in the autoload_paths but not in the eager_load_paths are not going to be loaded in production. What this means is that if file paths outside of app/ are in your config.autoload_paths and not in config.eager_load_paths (for example, lib/), these files will no longer load in deployed environments.


In my case I had a file called calendar.rb in the lib folder.

class Calendar < Struct.new(:view, :date, :callback)
...
end


and I was trying to use this class in a helper:


module CalendarHelper

  include ActionView::Helpers::OutputSafetyHelper

  include ActionView::Helpers::TagHelper

  include ActionView::Context
  def calendar(date = Date.current, &block)
    Calendar.new(self, date,  block).display
  end

...
end 


In my application.rb I had next configuration:

config.autoload_paths += %W(#{config.root}/lib)

But when I was trying to call Calendar.new from my helper, I was getting an error. Strange errors regarding missing requires and dependencies.


ActionView::Template::Error (uninitialized constant CalendarHelper::Calendar):

So what I had to do was change the configuration

# config/application.rb
config.eager_load_paths << Rails.root.join('lib')

And now everything works fine


Tuesday, August 08, 2017

How to connect the localhost Rails site via Mobile locally


If you want to test your app locally in a mobile or tablet, without the need to have a server, you can try ngrok.  Ngrok is a very cool, lightweight tool that creates a secure tunnel on your local machine along with a public URL you can use for browsing your local site.

It is very simple to use. Follow these steps:


Step 1

Download ngrok and install it.



Step 2

Run your Rails app:
$ rails s


Step 3

Go to the directory where you extracted the zip file and run it.

$  ./ngrok http 3000



Step 4
You can now access the Rails app from the URL displayed in the ngrok output. It will be something like: http://2ec640eb.ngrok.io


Tuesday, April 04, 2017

Heroku: Deploying with GIT



In this post I will explain how to deploy to Heroku directly through GIT. In order to see what git tree your Heroku repo is using, try:

$ git ls-remote git@heroku.com:APP-NAME.git

To find out the Heroku git repository name, you can also try

$ heroku info --app APP-NAME
=== app-name
Addons:
Auto Cert Mgmt:
Collaborators:
Dynos:
Git URL:
...

Right now, you know the Heroku git repository name, but you don't have a remote branch to push to.
Your Heroku app starts with a blank repository, it has no branches and no code. So the first time you deploy, you’ll need to specify a remote branch to push to.

For instance, imagine you have a server for Production where you deploy the APP-NAME, so you can create the remote called "pro-heroku".


$ git remote add pro-heroku https://git.heroku.com/APP-NAME.git

And now, if you have the git branch called "production" and we need to deploy this branch to Production, then you can try:

$ git push pro-heroku production:master

This will push your local branch production to the remote branch master in pro-heroku so APP-NAME will get deployed with the code in production branch.


I hope this post helps, if you have any comment or something please don't hesitate to add your comments.

Wednesday, November 30, 2016

How To Backup PostgreSQL Databases



Backups are an essential component in any kind of data storage plan. Fortunately, PostgreSQL gives you the utilities necessary to effectively backup your important information.

PostgreSQL includes a utility called "pg_dump" that can be used to dump a database into a file for backup purposes.

pg_dump 'database' > 'file_backup'

You can include user, host and port in the previous command if you need it:

pg_dump -U 'user_name' -h 'host' -p 'port' 'database' > 'file_backup'


To restore the backup created by pg_dump, you can redirect the file into psql standard input:



psql 'empty_database' < 'file_backup'

Monday, September 05, 2016

Rails: Custom Authentication Strategies With Devise and Warden


You're probably familiar with Devise. Devise is a flexible authentication solution for Rails based on Warden

Warden uses strategies to try to authenticate sessions. However, it provides no strategy, you have to implement them yourself. Devise implements a few that you may already know.

  • Devise Model Module
Models are more commonly known as Database Authenticatable, Rememberable, Trackable, Confirmable, etc.
When you install and bootstrap Devise in your project you should see something like this in the model User:

class User < ActiveRecord::Base
    devise :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable
  end


Since we want to write our own Authentication Implementation, we must follow suit and write a Model.


require 'devise/strategies/custom_authenticatable'

module Devise
  def self.bcrypt(klass, password)
    ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
    Devise::Encryptor.digest(klass, password)
  end

  module Models
    # Authenticatable Module, responsible for hashing the password and
    # validating the authenticity of a user while signing in.
    #
    # == Options
    #
    # DatabaseAuthenticatable adds the following options to devise_for:
    #
    #   * +pepper+: a random string used to provide a more secure hash. Use
    #     `rake secret` to generate new keys.
    #
    #   * +stretches+: the cost given to bcrypt.
    #
    # == Examples
    #
    #    User.find(1).valid_password?('password123')         # returns true/false
    #
    module CustomAuthenticatable
      extend ActiveSupport::Concern

      included do
        after_update :send_password_change_notification, if: :send_password_change_notification?

        attr_reader :password, :current_password
        attr_accessor :password_confirmation
      end

      def self.required_fields(klass)
        [:encrypted_password] + klass.authentication_keys
      end

      # Generates a hashed password based on the given value.
      # For legacy reasons, we use `encrypted_password` to store
      # the hashed password.
      def password=(new_password)
        @password = new_password
        self.encrypted_password = password_digest(@password) if @password.present?
      end

      # Verifies whether a password (ie from sign in) is the user password.
      def valid_password?(password)
        Devise::Encryptor.compare(self.class, encrypted_password, password)
      end

      # Set password and password confirmation to nil
      def clean_up_passwords
        self.password = self.password_confirmation = nil
      end

      # Update record attributes when :current_password matches, otherwise
      # returns error on :current_password.
      #
      # This method also rejects the password field if it is blank (allowing
      # users to change relevant information like the e-mail without changing
      # their password). In case the password field is rejected, the confirmation
      # is also rejected as long as it is also blank.
      def update_with_password(params, *options)
        current_password = params.delete(:current_password)

        if params[:password].blank?
          params.delete(:password)
          params.delete(:password_confirmation) if params[:password_confirmation].blank?
        end

        result = if valid_password?(current_password)
                   update_attributes(params, *options)
                 else
                   self.assign_attributes(params, *options)
                   self.valid?
                   self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
                   false
                 end

        clean_up_passwords
        result
      end

      # Updates record attributes without asking for the current password.
      # Never allows a change to the current password. If you are using this
      # method, you should probably override this method to protect other
      # attributes you would not like to be updated without a password.
      #
      # Example:
      #
      #   def update_without_password(params, *options)
      #     params.delete(:email)
      #     super(params)
      #   end
      #
      def update_without_password(params, *options)
        params.delete(:password)
        params.delete(:password_confirmation)

        result = update_attributes(params, *options)
        clean_up_passwords
        result
      end

      # Destroy record when :current_password matches, otherwise returns
      # error on :current_password. It also automatically rejects
      # :current_password if it is blank.
      def destroy_with_password(current_password)
        result = if valid_password?(current_password)
                   destroy
                 else
                   self.valid?
                   self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
                   false
                 end

        result
      end

      # A callback initiated after successfully authenticating. This can be
      # used to insert your own logic that is only run after the user successfully
      # authenticates.
      #
      # Example:
      #
      #   def after_database_authentication
      #     self.update_attribute(:invite_code, nil)
      #   end
      #
      def after_database_authentication
      end

      # A reliable way to expose the salt regardless of the implementation.
      def authenticatable_salt
        encrypted_password[0,29] if encrypted_password
      end

      def send_password_change_notification
        send_devise_notification(:password_change)
      end

      protected

      # Hashes the password using bcrypt. Custom hash functions should override
      # this method to apply their own algorithm.
      #
      # See https://github.com/plataformatec/devise-encryptable for examples
      # of other hashing engines.
      def password_digest(password)
        Devise::Encryptor.digest(self.class, password)
      end

      def send_password_change_notification?
        self.class.send_password_change_notification && encrypted_password_changed?
      end

      module ClassMethods
        Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)

        # We assume this method already gets the sanitized values from the
        # DatabaseAuthenticatable strategy. If you are using this method on
        # your own, be sure to sanitize the conditions hash to only include
        # the proper fields.
        def find_for_database_authentication(conditions)
          find_for_authentication(conditions)
        end
      end
    end
  end
end



Next we need to register our Model with Devise. We use Devise#add_module to do this. We can do this inside the file devise.rb that you can see in the folder config/initializers. Just add it to the top of the file.


Devise.add_module(:custom_authenticatable, {
   strategy: true,
   controller: :sessions,
   model: 'devise/models/custom_authenticatable',
   route: :session,
})


Without all of those options, Devise and Rails’ Router won’t know to delegate Requests to SessionController into your Module.

  • Warden Strategy
A strategy is a place where you can put logic related to authentication. Any strategy inherits from Warden::Strategies::Base.

The Warden::Strategies.add method is a simple way to provide custom strategies. You must declare an authenticate! method. You may provide a valid? method. The valid method should return true or false depending on if the strategy is a valid one for the request.




require 'devise/strategies/authenticatable'

module Devise
  module Strategies
    class CustomAuthenticatable < Authenticatable


      def authenticate!
        resource  = password.present? && mapping.to.find_for_database_authentication(authentication_hash)
        hashed = false
        if validate(resource){ hashed = true; resource.valid_password?(password) && resource.role.is_active? }
          remember_me(resource)
          resource.after_database_authentication
          success!(resource)
        end

        mapping.to.new.password = password if !hashed && Devise.paranoid
        fail(:not_found_in_database) unless resource
      end


    end
  end
end

Warden::Strategies.add(:custom_authenticatable, Devise::Strategies::CustomAuthenticatable)


In this scenario, I need to verify that user is active or not. So I created my own Strategy and I added the necessary logic for this project.  Inactive users can not do log in.

One important thing. In order to use my new authentication strategy, you must modify your User model and add something like this:

class User < ActiveRecord::Base
    devise :custom_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable
  end

Thursday, August 25, 2016

Cache Strategies for Rails: Low level caching




Sometimes we take a look at our log entries and we can see that some queries are taking a lot of time, maybe because the query is too heavy, or maybe because we are calling several queries in order to paint all the necessary information.


Low-level caching entails using the Rails.cache object directly to cache any information. For instance, I am envisioning the thypical scenario where we need to show a dropdown with all cities of a country. Maybe this query it is not heavy, but several queries at the same time like this, may affect to the performance. So in this case could be interesting save this query in the cache:

The  application has a Country model with an instance method returning all cities by country. Obviously we hace another model called City. The data returned by this method would be perfect for low-level caching. It will read a value from the cache if it available; otherwise it will execute a block passed to it and return the result:


# country.rb

def all_cities_by_country
  Rails.cache.fetch("cities_by_country_#{self.id}") do
    City.all.where("cities.country_id = ?",self.id)
  end
end

Now you could be thinking what happen if the admin creates a new city in the database? No problem, we have two possibilities, we could add to the key the column updated_at, so in this way each time admin updates the table the cache will be updated the next time user calls this method.
The other option could be create a callback in the model, so any time the table is updated we can call a private method that will update the cache.