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.

Accessing helper modules into decorate with Rails 4

Additionally, a decorator has access to Rails helper modules via the helper proxy method. This is useful when you want to hide complex logic from the templates.

class PersonDecorator < Draper::Decorator
  delegate_all

  def author_headline
    if author == helper.current_user
      h.content_tag(:h3, 'You')
    else
      h.content_tag(:h3, author.name)
    end
  end
end

Now in your template you just call @person.author_headline and you are done. No conditions in the template. Your designers will be thankful!

Access current_user into decorate like below.

h.current_user

Friday, May 15, 2015

Custom Flash Types In Rails 4

This small feature may help clean up some code. You can register your own flash types to use in redirect_to calls and in templates. For example:

# app/controllers/application_controller.rb
class ApplicationController
  add_flash_types :error, :catastrophe
end
 
# app/controllers/things_controller.rb
class ThingsController < ApplicationController
  def create
    # ... create a thing
  rescue Error => e
    redirect_to some_path, :error => e.message
  rescue Catastrophe => e
    redirect_to another_path, :catastrophe => e.message
  end
end
 
# app/views/layouts/application.html.erb
<div class="error"><%= error %></div>
<div class="catastrophe"><%= catastrophe %></div>




Thursday, May 14, 2015

Renamed Callbacks in Rails 4

Action callbacks in controllers have been renamed from *_filter to *_action.
For example:

class UsersController < ApplicationController
  before_action :set_user, :except => [:index, :new, :create}
  before_action :require_the_president, :only => [:fire_the_missiles]
 
  private
 
  def set_user
    @user = somehow_find_and_set_the_user(params[:id])
  end
 
  def require_the_president
    @user.is_the_president?
  end
end 

The old *_filter callbacks still work and are not deprecated; so, you can still use them if you wish.

Streaming, via ActionController::Live

The new ActionController::Live module provides the ability to stream data to clients. Simply include the module into a controller to enable your app to send arbitrary streamed data. You'll have to use a threaded server, like thin and puma, in order to stream data; actions from streaming controllers run in a separate thread.

Here's an example from the Rails 4 documentation:

class MyController < ActionController::Base
  include ActionController::Live
 
  def stream
    response.headers['Content-Type'] = 'text/event-stream'
    100.times {
      response.stream.write "hello world\n"
        sleep 1
    }
    response.stream.close
  end
end

As the docs note, there are three things to keep in mind:

  • You must write any headers before you call write or close on the response stream.
  • You have to call close on the response stream when you're finished writing data.
  • Ensure that your actions are thread-safe, as they will run in a separate thread.

Routing Concerns

Routing Concerns is an attempt to DRY up your config/routes.rb. The basic idea is to define common sub-resources (like comments) as concerns and include them in other resources/routes. Here's the obvious example:

concern :commentable do
  resources :comments
end

concern :remarkable do
  resources :remarks
end

resources :posts, :concerns => :commentable 
resources :articles, :concerns => [:commentable, :remarkable] # can include several

The above is equivalent to the following Rails 3 code:

resources :posts do
  resources :comments
end

resources :articles do
  resources :comments
  resources :remarks
end

Personally, I'm not sure this adds much value; perhaps it makes sense for large applications with hundreds of routes.

Friday, April 17, 2015

Current request url with host name in rails

# request.env["REQUEST_URI"]
It return request url only without parameter.

http://www.google.com

# request.env["HTTP_REFERER"]

It return url with parameter.

http://www.google.com?q=text

Tuesday, March 31, 2015

Difference between nil and false in ruby

The differences of the methods nil and false are:

- nil cannot be a value, where as a false can be a value
- A method returns true or false in case of a predicate, other wise nil is returned.
- false is a boolean data type, where as nil is not.
- nil is an object for NilClass, where as false is an object of for FalseClass

In sort::

False is a boolean datatype 
Nil is not a data type 

Wednesday, March 25, 2015

Difference between "include" and "extend" in Ruby?

extend: 
If you're using a module, that means you're bringing all the methods into your class. If you extend a class with a module, that means you're "bringing in" the module's methods as class methods.

include:
If you include a class with a module, that means you're "bringing in" the module's methods as instance methods.

EX:


 module A
   def say
     puts "this is module A"
   end
 end

 class B
   include A
 end

 class C
   extend A
 end

Output:

 B.say
 => undefined method 'say' for B:Class



 B.new.say
 => this is module A



 C.say
 => this is module A



 C.new.say
 => undefined method 'say' for C:Class

What is the use of 'require' in ruby ?

Please run below commands on rails console.

Input:     require "file_name"
Output:  true => load the file

Input:    require "file_name"
Output: false => already load

Input:    require "file_name"
Output: Error => Need to add this file

RUBY:: Form submit by webdriver

Use of selenium webdriver

require 'rubygems'
require 'selenium-webdriver'
require 'json'

For remote access
caps = Selenium::WebDriver::Remote::Capabilities.chrome
driver = Selenium::WebDriver.for(:remote, :url => "server_url", :desired_capabilities => caps)

For local access
driver = Selenium::WebDriver.for :firefox


driver.navigate.to "http://www.facebook.com/"
driver.find_element(:id, 'email').send_keys "aemailcom"
driver.find_element(:id, 'pass').send_keys "apssword"
driver.find_element(:xpath, "//input[@value='Log In']").click
puts driver.title
driver.quit

Use of watir webdriver

require 'rubygems'
require 'watir-webdriver'

driver = Watir::Browser.new :firefox
driver.navigate.to "http://www.facebook.com/"
driver.find_element(:id, 'email').send_keys "aemailcom"
driver.find_element(:id, 'pass').send_keys "apssword"
driver.find_element(:xpath, "//input[@value='Log In']").click
puts driver.url
driver.close

Tuesday, March 24, 2015

Install selenium-webdriver and watir-webdriver for ruby

If you are using Ruby for test automation then you probably are already familiar with developing in Ruby. To add Selenium and watir to your Ruby environment run the following command from a command-line.

gem install selenium-webdriver

and

gem install watir-webdriver

Thursday, March 19, 2015

Ruby's reserved words

Reserved word     Description
BEGIN             Code, enclosed in { and }, to run before the program runs.
END               Code, enclosed in { and }, to run when the program ends.
alias             Creates an alias for an existing method, operator, or global variable.
and               Logical operator; same as && except and has lower precedence.
begin             Begins a code block or group of statements; closes with end.
break             Terminates a while or until loop or a method inside a block.
\case             Compares an expression with a matching when clause; closes with end.
class             Defines a class; closes with end.
def               Defines a method; closes with end.
defined?          Determines if a variable, method, super method, or block exists.
do                Begins a block and executes code in that block; closes with end.
else              Executes if previous conditional, in if, elsif, unless, or when, is not true.
elsif             Executes if previous conditional, in if or elsif, is not true.
end               Ends a code block (group of statements) starting with begin, def, do, if, etc.
ensure            Always executes at block termination; use after last rescue.
false             Logical or Boolean false, instance of FalseClass. (See true.)
for               Begins a for loop; used with in.
if                Executes code block if true. Closes with end. 
module            Defines a module; closes with end.
next              Jumps before a loop's conditional.
nil               Empty, uninitialized variable, or invalid, but not the same as zero; object of NilClass.
not               Logical operator; same as !.
or                Logical operator; same as || except or has lower precedence.
redo              Jumps after a loop's conditional.
rescue            Evaluates an expression after an exception is raised; used before ensure.
retry             Repeats a method call outside of rescue; jumps to top of block (begin) if inside rescue.
return            Returns a value from a method or block. May be omitted.
self              Current object (invoked by a method).
super             Calls method of the same name in the superclass. The superclass is the parent of this class.
then              A continuation for if, unless, and when. May be omitted.
true              Logical or Boolean true, instance of TrueClass.
undef             Makes a method in current class undefined.
unless            Executes code block if conditional statement is false.
until             Executes code block while conditional statement is false.
when              Starts a clause (one or more) under case.
while             Executes code while the conditional statement is true.
yield             Executes the block passed to the method.
_ _FILE_ _        Name of current source file.
_ _LINE_ _     Number of current line in the current source file.

Convert json to html view

json = {"employees":[
    {"firstName":"John", "lastName":"Doe"},
    {"firstName":"Anna", "lastName":"Smith"},
    {"firstName":"Peter", "lastName":"Jones"}
]}

function syntaxHighlight(json) {
    if (typeof json != 'string') {
         json = JSON.stringify(json, undefined, 2);
    }
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key';
            } else {
                cls = 'string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean';
        } else if (/null/.test(match)) {
            cls = 'null';
        }
        return '<span class="' + cls + '">' + match + '</span>';
    });
}

syntaxHighlight(json)

Output::