Wednesday, November 4, 2015

Rails Models

Rails Models

  Generating models

$ rails g model User

  Associations

belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many

belongs_to :author,
  class_name: 'User',
  dependent: :destroy  // delete this

  Has many

has_many :comments, :order => "posted_on"
has_many :comments, :include => :author
has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
has_many :tracks, :order => "position", :dependent => :destroy
has_many :comments, :dependent => :nullify
has_many :tags, :as => :taggable
has_many :reports, :readonly => true
has_many :subscribers, :through => :subscriptions, :source => :user
has_many :subscribers, :class_name => "Person", :finder_sql =>
    'SELECT DISTINCT people.* ' +
    'FROM people p, post_subscriptions ps ' +
    'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
    'ORDER BY p.first_name'

  Many-to-many

If you have a join model:
class Programmer < ActiveRecord::Base
  has_many :assignments
  has_many :projects, :through => :assignments
end

class Project < ActiveRecord::Base
  has_many :assignments
  has_many :programmers, :through => :assignments
end

class Assignment
  belongs_to :project
  belongs_to :programmer
end
Or HABTM:
has_and_belongs_to_many :projects
has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
has_and_belongs_to_many :nations, :class_name => "Country"
has_and_belongs_to_many :categories, :join_table => "prods_cats"
has_and_belongs_to_many :categories, :readonly => true
has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
"DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}"

  Polymorphic associations

class Post
  has_many :attachments, :as => :parent
end

class Image
  belongs_to :parent, :polymorphic => true
end
And in migrations:
create_table :images do |t|
  t.references :post, :polymorphic => true
end

  Migrations

  Run migrations

$ rake db:migrate

  Migrations

create_table :users do |t|
  t.string :name
  t.text   :description

  t.primary_key :id
  t.string
  t.text
  t.integer
  t.float
  t.decimal
  t.datetime
  t.timestamp
  t.time
  t.date
  t.binary
  t.boolean
end

options:
  :null (boolean)
  :limit (integer)
  :default
  :precision (integer)
  :scale (integer)

  Tasks

create_table
change_table
drop_table
add_column
change_column
rename_column
remove_column
add_index
remove_index

  Associations

t.references :category   # kinda same as t.integer :category_id

# Can have different types
t.references :category, polymorphic: true

  Add/remove columns

$ rails generate migration RemovePartNumberFromProducts part_number:string

class RemovePartNumberFromProducts < ActiveRecord::Migration
  def up
    remove_column :products, :part_number
  end

  def down
    add_column :products, :part_number, :string
  end
end

  Validation

  Validate checkboxes

class Person < ActiveRecord::Base
  validates :terms_of_service, :acceptance => true
end

  Validate associated records

class Library < ActiveRecord::Base
  has_many :books
  validates_associated :books
end

  Confirmations (like passwords)

class Person < ActiveRecord::Base
  validates :email, :confirmation => true
end

  Validate format

class Product < ActiveRecord::Base
  validates :legacy_code, :format => { :with => /\A[a-zA-Z]+\z/,
    :message => "Only letters allowed" }
end

  Validate length

class Person < ActiveRecord::Base
  validates :name, :length => { :minimum => 2 }
  validates :bio, :length => { :maximum => 500 }
  validates :password, :length => { :in => 6..20 }
  validates :registration_number, :length => { :is => 6 }

  validates :content, :length => {
    :minimum   => 300,
    :maximum   => 400,
    :tokenizer => lambda { |str| str.scan(/\w+/) },
    :too_short => "must have at least %{count} words",
    :too_long  => "must have at most %{count} words"
  }
end

  Numeric

class Player < ActiveRecord::Base
  validates :points, :numericality => true
  validates :games_played, :numericality => { :only_integer => true }
end

  Non-empty

class Person < ActiveRecord::Base
  validates :name, :login, :email, :presence => true
end

  custom

class Person < ActiveRecord::Base
  validate :foo_cant_be_nil

  def foo_cant_be_nil
    errors.add(:foo, 'cant be nil')  if foo.nil?
  end
end

  API

items = Model.find_by_email(email)
items = Model.where(first_name: "Harvey")

item = Model.find(id)

item.serialize_hash
item.new_record?

item.create     # Same an #new then #save
item.create!    # Same as above, but raises an Exception

item.save
item.save!      # Same as above, but raises an Exception

item.update
item.update_attributes
item.update_attributes!

item.valid?
item.invalid?

  Mass updates

# Updates person id 15
Person.update 15, name: "John", age: 24
Person.update [1,2], [{name: "John"}, {name: "foo"}]

  Joining

Student.joins(:schools).where(:schools => { :type => 'public' })
Student.joins(:schools).where('schools.type' => 'public' )

  Serialize

class User < ActiveRecord::Base
  serialize :preferences
end

user = User.create(:preferences => { "background" => "black", "display" => large })
You can also specify a class option as the second parameter that’ll raise an exception if a serialized object is retrieved as a descendant of a class not in the hierarchy.
class User < ActiveRecord::Base
  serialize :preferences, Hash
end

user = User.create(:preferences => %w( one two three ))
User.find(user.id).preferences    # raises SerializationTypeMismatch

  Overriding accessors

class Song < ActiveRecord::Base
  # Uses an integer of seconds to hold the length of the song

  def length=(minutes)
    write_attribute(:length, minutes.to_i * 60)
  end

  def length
    read_attribute(:length) / 60
  end
end

  Callbacks

after_create
after_initialize
after_validation
after_save
after_commit

Rails Migration

Migrations methods:

  • add_column
  • add_index
  • change_column
  • change_table
  • create_table
  • drop_table
  • remove_column
  • remove_index
  • rename_column
Basic format YYYYMMDDHHMMSS_create_products.rb

Supported types

  • :binary
  • :boolean
  • :date
  • :datetime
  • :decimal
  • :float
  • :integer
  • :primary_key
  • :string
  • :text
  • :time
  • :timestamp especial type:
  • :references

create_table

Commands to create migrations

$ rails generate model Product name:string description:text
$ rails generate migration AddPartNumberToProducts part_number:string
$ rails generate migration RemovePartNumberFromProducts part_number:string
$ rails generate migration AddDetailsToProducts part_number:string price:decimal

change_table

  • add_column
  • add_index
  • add_timestamps
  • create_table
  • remove_timestamps
  • rename_column
  • rename_index
  • rename_table

Running Migrations

$ rake db:migrate VERSION=20080906120000
$ rake db:rollback
$ rake db:rollback STEP=3
$ rake db:migrate:redo STEP=3
$ rake db:reset  #drop database and recreate it
$ rake db:migrate:up VERSION=20080906120000

Migrations commands

rake db:migrate         # Migrate the database (options: VERSION=x, VERBOSE=false).
rake db:migrate:status  # Display status of migrations
rake db:rollback        # Rolls the schema back to the previous version (specify steps w/ STEP=n).
rake db:test:prepare    # Rebuild it from scratch according to the specs defined in the development database

more Database commands (rake -T db)

rake db:create          # Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in t...
rake db:drop            # Drops the database for the current Rails.env (use db:drop:all to drop all databases)
rake db:fixtures:load   # Load fixtures into the current environment's database.
rake db:schema:dump     # Create a db/schema.rb file that can be portably used against any DB supported by AR
rake db:schema:load     # Load a schema.rb file into the database
rake db:seed            # Load the seed data from db/seeds.rb
rake db:setup           # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)
rake db:structure:dump  # Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql
rake db:version         # Retrieves the current schema version number

Monday, August 10, 2015

A Look at Rails 5

No more typing rake commands

In Rails 5 all the current rake commands will be accessible via the rails command. When you want to run a migration, you will type rake db:migrate in Rails 4.

In Rails 5 this will become rails db:migrate.

The reason for this change is that currently it's not very logical which command has to go through rake and which command should go through rails. When you're working with rails for a longer time it becomes second nature, but only because you remember it. For a newcomer, this is a big problem and makes learning rails confusing.

Restart your app with a rake command

rake restart

Rails 5 will support only Ruby 2.2.1 and above versions.

Wednesday, August 5, 2015

Rake is a utility similar to make in Unix. You can say Rake is the make of ruby - the R uby m AKE. Rails defines a number of tasks to help you.
Here is a list of various important commands supported by Rake:

  • rake db:fixtures:load - Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y
  • rake db:migrate - Migrate the database through scripts in db/migrate. Target specific version with VERSION=x
  • rake db:schema:dump - Create a db/schema.rb file that can be portably used against any DB supported by AR.
  • rake db:schema:load - Load a schema.rb file into the database.
  • rake db:sessions:clear - Clear the sessions table.
  • rake db:sessions:create - Creates a sessions table for use with CGI::Session::ActiveRecordStore.
  • rake db:structure:dump - Dump the database structure to a SQL file.
  • rake db:test:clone - Recreate the test database from the current environment's database schema.
  • rake db:test:clone_structure - Recreate the test databases from the development structure.
  • rake db:test:prepare - Prepare the test database and load the schema.
  • rake db:test:purge - Empty the test database.
  • rake doc:appBuild the app HTML Files.
  • rake doc:clobber_app - Remove rdoc products.
  • rake doc:clobber_plugins - Remove plugin documentation.
  • rake doc:clobber_rails Remove rdoc products.
  • rake doc:plugins - Generate documation for all installed plugins.
  • rake doc:rails - Build the rails HTML Files.
  • rake doc:reapp - Force a rebuild of the RDOC files
  • rake doc:rerails - Force a rebuild of the RDOC files
  • rake log:clear - Truncates all *.log files in log/ to zero bytes
  • rake rails:freeze:edge - Lock this application to latest Edge Rails. Lock a specific revision with REVISION=X.
  • rake rails:freeze:gems - Lock this application to the current gems (by unpacking them into vendor/rails)
  • rake rails:unfreeze - Unlock this application from freeze of gems or edge and return to a fluid use of system gems
  • rake rails:update - Update both scripts and public/javascripts from Rails.
  • rake rails:update:javascripts - Update your javascripts from your current rails install.
  • rake rails:update:scripts - Add new scripts to the application script/ directory.
  • rake stats - Report code statistics (KLOCs, etc) from the application.
  • rake test - Test all units and functionals
  • rake test:functionals - Run tests for functionalsdb:test:prepare
  • rake test:integration - Run tests for integrationdb:test:prepare
  • rake test:plugins - Run tests for pluginsenvironment
  • rake test:recent - Run tests for recentdb:test:prepare
  • rake test:uncommitted - Run tests for uncommitteddb:test:prepare
  • rake test:units - Run tests for unitsdb:test:prepare
  • rake tmp:cache:clear - Clears all files and directories in tmp/cache
  • rake tmp:clear - Clear session, cache, and socket files from tmp/
  • rake tmp:create - Creates tmp directories for sessions, cache, and sockets
  • rake tmp:sessions:clear - Clears all files in tmp/sessions
  • rake tmp:sockets:clear - Clears all ruby_sess.* files in tmp/sessions

Wednesday, June 10, 2015

How to get the current timezone with Javascript

Please include these cdns into your HTML document.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js"></script>

Invoke the script by calling:

> var timezone = jstz.determine();
> timezone.name();
"Asia/Kolkata"

Tuesday, June 2, 2015

Difference between to_s and inspect in Ruby

While running a script in Ruby, we usually want to log data from objects for debugging purpose. puts, p, logger methods are used to log along with to_s, inspect methods to log object. This tutorial will give brief about each method and when to use which one.


1. to_s

to_s is very common method used by Ruby programmers to get String representation of object on which it is called. For example,
considering fixnum,

12345.to_s => '12345'

Similarly if you try to use to_s method on Model/ActiveRecord object in Rails, it will give something like,

User.first.to_s
#<User:0x007fd15cc57238>

Which is object's representation in string. User: Class name, 0x007fd15cc57238: based on object id.

Using String Interpolation:
Whenever you use String Interpolation, Ruby calls by default to_s method on objects used in the String interpolation before printing output. For example,

user = User.first
puts "This is #{user} information"
"This is #<User:0x007fefb2002428> information"

This show that while processing string interpolation user object is converted to to_s internally.

2. inspect

inspect method is more of a developer-friendly version of to_s. For Model/ActiveRecord you can check out definition of inspect on APIDock
Considering same example as above,

user = User.first
puts "This is #{user.inspect} information"
This is #<User id: 1, email: "username@example.com", encrypted_password: "$2a$10$D57y73Q9HUXG9Hym3bLl8.MizOdTRxd6NQH6snHi4Q....", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: "2014-10-15 11:19:09", sign_in_count: 13, current_sign_in_at: "2014-10-21 20:10:18", last_sign_in_at: "2014-10-20 17:37:27", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-06-30 17:41:06", updated_at: "2014-10-21 20:10:18"> information"

This clearly depicts how much useful inspect is instead of to_s on objects for logging and debugging purposes.

3. p vs puts

When you use puts for printing, then puts internally uses to_s on objects before processing inputs, while p uses inspect on objects before processing inputs.
E.g. Again considering same example,

user = User.first
puts user
#<User:0x007fefb0c690b0>

This just has converted object's reference using to_s
Now tryng with p

p user
#<User id: 1, email: "username@example.com", encrypted_password: "$2a$10$D57y73Q9HUXG9Hym3bLl8.MizOdTRxd6NQH6snHi4Q....", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: "2014-10-15 11:19:09", sign_in_count: 13, current_sign_in_at: "2014-10-21 20:10:18", last_sign_in_at: "2014-10-20 17:37:27", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-06-30 17:41:06", updated_at: "2014-10-21 20:10:18">

Thus, you may prefer using p instead of to_s if you are looking purely for logging/ debugging purposes. Otherwise use of these methods purely depends on the required functionality though. 

Wednesday, May 20, 2015

Deprecated Finders With Rails 4

Rails 4 deprecates the old-style finder option hashes, as well as all dynamic finder methods (with the exception of find_by_... and find_by_...). Instead, you'll use where:

  • find_all_by_... can be rewritten using where(...).
  • find_last_by_... can be rewritten using where(...).last.
  • scoped_by_... can be rewritten using where(...).
  • find_or_initialize_by_... can be rewritten using where(...).first_or_initialize.
  • find_or_create_by_... can be rewritten using find_or_create_by(...) or where(...).first_or_create.
  • find_or_create_by_...! can be rewritten using find_or_create_by!(...) or where(...).first_or_create!.
The deprecated finders gem will be included as a dependency in 4.0. and removed in 4.1. The gem, however, will be around and maintained until 5.0.

FastAPI: The Modern Python Web Framework

  Introduction to FastAPI: The Modern Python Web Framework The world of web frameworks has always been competitive — from Django and Flask ...