An instance variable has a name beginning with @
, and its scope is confined to whatever object self refers to. Two different objects, even if they belong to the same class, are allowed to have different values for their instance variables. From outside the object, instance variables cannot be altered or even observed (i.e., ruby's instance variables are never public) except by whatever methods are explicitly provided by the programmer.
As with globals, instance variables have the nil value until they are initialized. Instance variables of ruby do not need declaration. This implies a flexible structure of objects. In fact, each instance variable is dynamically appended to an object when it is first referenced.
Example of instance variable in Ruby:
class InstanceVariableExample
def initialize
@name = 'Instance Variable'
@message = 'I am an instance variable of this class'
end
def display_name
puts @name
end
def display_message
puts @message
end
end
obj = InstanceVariableExample.new
obj.display_name
#=> Instance Variable
obj.display_message
# I am an instance variable of this class
In above example you can see that @name
and @message
starts with the @
symbol and both are the instance variable of the class mentioned in example. You can clearly see in the example that instance variables can be accessible inside any method of the class.
Ruby is a true object oriented programming language. Classes can be considered as blueprint or container for similar kind of objects. Classes allows us to create objects and methods which are used by objects of that class.
Creating a class is very simple in Ruby. It uses class keyword followed by name of the class. Look at the following example:
class ExampleClass
#you can add some working code here
end
We can initialize object of a class by invoking new
method on class.
obj1 = ExampleClass.new
obj2 = ExampleClass.new
Here we have created two objects of ExampleClass
.
Arrays are ordered, integer-indexed collections of any object. Array indexing starts at 0, as in C or Java. A negative index is assumed to be relative to the end of the array—that is, an index of -1 indicates the last element of the array, -2 is the next to last element in the array, and so on. Look the following example:
arr = Array.new
arr << 'insert'
arr << 'elements'
arr << 'into'
arr << 'array'
puts arr
=> ["insert", "elements", "into", "array"]
A Hash is a collection of key-value pairs. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. Hashes enumerate their values in the order that the corresponding keys were inserted.
Hashes have a default value that is returned when accessing keys that do not exist in the hash. By default, that value is nil.
h = Hash.new
h[:name] = 'Lorem Ipsum'
h[:email] = 'email@example.com'
h[:phone_number] = '1234567890'
puts h
{:name=>"Lorem Ipsum", :email=>"email@example.com", :phone_number=>"1234567890"}
Cheers!!!
Look at the following snippets:
{}.empty?
=> true
Because the hash object has no key-value pair in it hance it is empty.
{}.present?
=> false
Same reason as above. But the main difference between both methods is that empty?
can be used in both Ruby and Rails but present?
can be used in Rails only. For verifying this try using present?
in two different consoles.
When you try present?
with rails console as:
{}.present?
=> false
But when you try present?
with irb console, you will get an error::
{}.present?
=> NoMethodError (undefined method `present?' for {}:Hash)
Distructive array methods are the methods which can change the original array once invoking on array. Distructive methods always used using the ! symbol.
Look at the following snippet:
a = [5,4,3,2,1]
=> [5,4,3,2,1]
a.sort!
=> [1,2,3,4,5]
puts a
=> [1,2,3,4,5]
On the other hand Non-distructive methods will only change the output but not the original array.
a = [5,4,3,2,1]
=> [5,4,3,2,1]
a.sort
=> [1,2,3,4,5]
puts a
=> [5,4,3,2,1]
sort method is only example, you can try with other built in array methods too provided by ruby. To check all built in array methods provided by ruby you can do following:
arr = Array.new
=> []
arr.methods
=> [:to_h, :include?, :&, :*, :+, :-, :at, :fetch, :last, :union, :difference, :intersection, :push, :append, :pop, :shift, :unshift, :each_index, :join, :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :filter!, :keep_if, :values_at, :delete_at, :delete_if, :reject!, :transpose, :fill, :assoc, :rassoc, :uniq!, :compact, :compact!, :flatten, :flatten!, :shuffle!, :shuffle, :sample, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :bsearch, :sort, :bsearch_index, :deconstruct, :count, :find_index, :select, :filter, :reject, :collect, :map, :first, :all?, :any?, :one?, :none?, :minmax, :|, :reverse_each, :zip, :take, :take_while, :drop, :<=>, :<<, :cycle, :drop_while, :==, :sum, :uniq, :[], :[]=, :insert, :empty?, :eql?, :index, :rindex, :replace, :clear, :max, :min, :inspect, :length, :size, :each, :reverse, :concat, :prepend, :reverse!, :to_ary, :to_a, :to_s, :delete, :pack, :slice, :slice!, :dig, :hash, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :slice_after, :slice_when, :chunk_while, :chain, :to_set, :lazy, :find, :entries, :sort_by, :grep, :grep_v, :detect, :find_all, :filter_map, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :tally, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :class, :display, :singleton_class, :clone, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :===, :=~, :!~, :nil?, :respond_to?, :freeze, :object_id, :send, :__send__, :!, :!=, :equal?, :__id__, :instance_eval, :instance_exec]
NOTE: You can only try with the collection methods like sort, flatten etc.
Ruby is a true object oriented programming language which comes with various features. Some of those key features are listed below:
attr_reader
works as a getter method in Ruby. When you use this you can only read/get the value of an attribute. But when you will try to update its value this will raise an exception.
Look at the following example:
class GetterSetter
attr_reader :name
def initialize()
@name = 'Lorem Ipsum'
end
end
obj = GetterSetter.new
# This will print the value of name and will be executed sussessfully
puts obj.name
=> "Lorem Ipsum"
# When you execute this line this will raise an exception
obj.name = 'Another Name'
=> NoMethodError (undefined method `name=' for #)
Did you mean? name
hence attr_reader
will work as getter method only.
attr_writer
works as a setter method in Ruby. When you use this you can only write/change the value of an attribute. But when you will try to read its value this will raise an exception.
Look at the following example:
class GetterSetter
attr_writer :name
def initialize()
@name = 'Lorem Ipsum'
end
end
obj = GetterSetter.new
# This will change the value of name and will be executed sussessfully
obj.name = 'Another Name'
=> "Another Name"
# When you execute this line this will raise an exception
puts obj.name
=> NoMethodError (undefined method `name' for #)
Did you mean? name=
hence attr_writer
will work as getter method only.
attr_accessor
will work as both getter and setter. When you use this you can read/get the value of attribute and change its value as well.
Look at the following example:
class GetterSetter
attr_accessor :name
def initialize()
@name = 'Lorem Ipsum'
end
end
obj = GetterSetter.new
# This will print the value of name and will be executed sussessfully
puts obj.name
=> "Lorem Ipsum"
# This will change the value of name and will be executed sussessfully
obj.name = 'Another Name'
=> "Another Name"
Now the main confusion is that when we should use which of these three. So the answer is very simple that if you only need to read the value of attributes you need to use attr_reader
and when you need to change the value of attribute you must use attr_writer
. But when you need both you should use attr_accessor
.
Modules are a way of grouping together methods, classes, and constants. Modules give you two major benefits. Modules provide a namespace and prevent name clashes and they also implement the mixin facility.
The main difference between classes and modules is that classes provide more ownership rather than objects. A class in Ruby can be instantiated but a standard module could not. Modules can used inside classes. Look atthe following example:
module Greetings
def welcome
puts 'Welcome to Ruby world.'
end
def hello
puts 'Hello! I am module.'
end
end
class Example
include Greetings
end
obj = Example.new
obj.welcome
=> "Welcome to Ruby world."
obj.hello
=> "Hello! I am module."
There are four ways to invoke a method in Ruby.
Let's see following example:
arr = Array.new
=> []
arr.object_id
=> 22020
arr.send(:object_id)
=> 22020
arr.send('object_id')
=> 22020
arr.method(:object_id).call
=> 22020
arr.method('object_id').call
=> 22020
arr::object_id
=> 22020
You can invoke any other method just like above on objects of any class.
self
is the keyword in Ruby that gives you the access to the current object. self can also be used for defining class level methods.
Look at the example below:
class Fish
def display_self
puts self
end
end
Fish.new.display_self
=> #
class Fish
# using self for accessing current object
def display_self
puts self
end
# using self for defining class methods
def self.display_self
puts self
end
end
Fish.new.display_self
=> #
Fish.display_self
=> Fish
self
is also known as default receiver of method calls.
Getter methods are used to retrieve values of instance variables of an object. It is common practice to have the getter method’s name match the instance variable’s name. Below is the example of creating a getter method in Ruby.
class Example
# initializing the name instance variable
def initialize(name)
@name = name
end
# getter method
def name
@name
end
end
obj = Example.new('Lorem Ipsum')
puts obj.name
=> "Lorem Ipsum"
Setter methods are used to change/write the value of instance variables of an object. Below is the example of creating a setter method in Ruby.
class Example
# initializing the name instance variable
def initialize(name)
@name = name
end
# setter method
def name=(value)
@name = value
end
end
obj = Example.new('Lorem Ipsum')
obj.name = 'Another Name'
class Example
# initializing the name instance variable
def initialize(name)
@name = name
end
# getter method
def name
@name
end
# setter method
def name=(value)
@name = value
end
end
obj = Example.new('Lorem Ipsum')
obj.name = 'Another Name'
puts obj.name
=> "Another Name"
Instead of writing getter and setter method separetly you can also use ruby keywords attr_reader
, attr_writer
for getting functions of getter and setter methods. attr_reader
will work as getter method and attr_writer
will work as setter method. There is one more alternative to use more shorter form that is attr_accessor
. If you use this this will work as both getter ans setter.
Let's have a look:
class Example
attr_reader :name
def initialize(name)
@name = name
end
end
obj = Example.new('Lorem Ipsum')
puts obj.name
=> "Lorem Ipsum"
This will work same as the class mentioned for getter method example.
class Example
attr_writer :name
def initialize(name)
@name = name
end
end
obj = Example.new('Lorem Ipsum')
obj.name = 'Another Name'
This will work same as the class mentioned for setter method example.
class Example
attr_accessor :name
def initialize(name)
@name = name
end
end
obj = Example.new('Lorem Ipsum')
obj.name = 'Another Name'
puts obj.name
=> "Another Name"
This will work same as the class mentioned for both getter and setter example.
Compact will remove nil
elements from array if there is any. Look at the following example:
arr = [1, 2, 3, nil, 4, 5, nil, 6, 7, 8, nil]
This array has three nil
elements. Now see the result of calling compact method on this array, you will get following example:
arr = [1, 2, 3, nil, 4, 5, nil, 6, 7, 8, nil]
arr.compact
=> [1, 2, 3, 4, 5, 6, 7, 8]
Now the task for you is to create a method which should return the same output as the compact method returns.
arr = [1, 2, 3, nil, 4, 5, nil, 6, 7, 8, nil]
def custom_compact(arr)
temp_arr = []
arr.map {|i| temp_arr << i unless i.nil? }
temp_arr
end
custom_compact(arr)
=> [1, 2, 3, 4, 5, 6, 7, 8]
This is how you can create your own compact method for removing nil elements from any given array. There are so many in built array methods which you might be asked during interview so you must try such logical things.
Cheers!!!
MVC(Model-View-Controller) is a software design pattern and this is conventionally followed by Rails. Let's briefly define each component of MVC.
Model: Model is the layer of the system responsible for representing business data and logic. In Rails models facilitates the creation and use of business objects whose data requires persistent storage to a database.
View: This represents the presentation layer in MVC pattern. Model data is populated on views so that users can see this data. View is also used to make requests for data, to perform certain actions like CRUD by users. In Rails whenever a user perform any action on view or make a request to retrive or submit data, this is first goes to controller via rails router and then appropriate controller gets loaded and then controller serves the requested actions.
Controller: Controller works as the mediater between Model and View, it makes the model data available to the view so it can display that data to the user, and it saves or updates user data to the model. Once a request from the view has been made by users, this is first received by the router and after the router has determined which controller to use for a request, the controller is responsible for making sense of the request, and producing the appropriate output.
In Rails, a controller has three possible ways to create HTTP response:
render
to create a full response to send back to the browser. This is mainly used while retriving information for any single orcollection of objects. This can be also be used for static pages as well.redirect_to
to send an HTTP redirect status code to the browser. This is mainly used while submitting data for create or update a record or delete a record from database.head
to create a response consisting solely of HTTP headers to send back to the browser.With strong parameters, Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been permitted.
The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for passing error messages, etc.
The flash is accessed via the flash method. Like the session, the flash is represented as a hash.
Shallow nesting is useful when you want to avoid deep level of nesting of resources. Shallow routes generate the collection actions scoped under the parent, so as to get a sense of the hierarchy, but to not nest the member actions. In other words, to only build routes with the minimal amount of information to uniquely identify the resource.
For example look at the example below:
resources :articles do
resources: :comments
end
Will generate routes for comments like this:
A Rails Concern is any module that extends ActiveSupport::Concern module. Consider the following example concern which has some class methods implemented:
module Scoppable
extend ActiveSupport::Concern
class_methods do
def created_in_current_month
start_date = DateTime.current.beginning_of_month
end_date = start_date.end_of_month
results(start_date, end_date)
end
def created_in_last_n_months(n)
start_date = (DateTime.current - n.months).beginning_of_month
end_date = start_date.end_of_month
results(start_date, end_date)
end
def results(sd, ed)
where('created_at BETWEEN ? AND ?', sd, ed)
end
end
end
Now you can use this concern into any of your model class. For example I am using this module into a model named Project.
class Project < ApplicationRecord
include Scoppable
end
Now when I run following query:
Project.created_in_current_month
this will return all the projects created in current month.
And when I run following query:
Project.created_in_last_n_months(10)
this will return all the projects created in last 10 month.
This is just an example and you can implement such concerns as per your needs.