Table of Contents
Ruby on Rails is a server-side web application development tool. Currently, it is one of the most popular frameworks and easy to learn. Even if it is easy to learn, programmers still get confused or get stuck at some point. Many questions start to arise and they look for the answers. So, we have prepared a list of 12 most asked questions about Ruby on Rails along with answers.
12 Most Asked Questions About Ruby on Rails
1. How to rename a database column in a Ruby on Rails migration?
Answer:
rename_column :table, :old_column, :new_column
You’ll probably want to create a separate migration to do this. (Rename FixColumnName
as you will.):
script/generate migration FixColumnName
# creates db/migrate/xxxxxxxxxx_fix_column_name.rb
Then edit the migration to do your will:
# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
def self.up
rename_column :table_name, :old_column, :new_column
end
def self.down
# rename back if you need or do something else or do nothing
end
end
For Rails 3.1 use:
While the up
and down
methods still apply, Rails 3.1 receives a change
method that “knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate down method”.
rails g migration FixColumnName
class FixColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
If you happen to have a whole bunch of columns to rename or something that would have required repeating the table name over and over again:
rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...
You could use change_table
to keep things a little neater:
class FixColumnNames < ActiveRecord::Migration
def change
change_table :table_name do |t|
t.rename :old_column1, :new_column1
t.rename :old_column2, :new_column2
...
end
end
end
Then just db:migrate
as usual or however, you go about your business.
For Rails 4:
While creating a Migration
for renaming a column, Rails 4 generates a change
method instead of up
and down
as mentioned in the above section. The generated change
method is:
$ > rails g migration ChangeColumnName
which will create a migration file similar to:
class ChangeColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
Alternative Answer:
You can also use rake db:rollback
, then edit your migration and again run rake db:migrate
.
However, if you have data in the column you don’t want to lose, then use rename_column
.
2. How to understand nil vs. empty vs. blank in Rails (and Ruby)?
Answer:
.nil?
can be used on any object and is true if the object is nil.
.empty?
can be used on strings, arrays, and hashes and returns true if:
- String length == 0
- Array length == 0
- Hash length == 0
Running .empty?
on something that is nil will throw a NoMethodError
.
That is where .blank?
comes in. It is implemented by Rails and will operate on any object as well as work like .empty?
on strings, arrays, and hashes.
nil.blank? == true
false.blank? == true
[].blank? == true
{}.blank? == true
"".blank? == true
5.blank? == false
0.blank? == false
.blank?
also evaluates true on strings which are non-empty but contain only whitespace:
" ".blank? == true
" ".empty? == false
Rails also provides .present?
, which returns the negation of .blank?
.
Array gotcha: blank?
will return false
even if all elements of an array are blank. To determine blankness in this case, use all?
with blank?
, for example:
[ nil, '' ].blank? == false
[ nil, '' ].all? &:blank? == true
Alternative Answer:
This table will help you understand better:
blank?
, present?
are provided by Rails.
3. Why do people use Heroku when AWS is present? What distinguishes Heroku from AWS?
Answer:
AWS / Heroku are both free for small hobby projects (to start with).
If you want to start an app right away, without much customization of the architecture, then choose Heroku.
If you want to focus on the architecture and to be able to use different web servers, then choose AWS. AWS is more time-consuming based on what service/product you choose but can be worth it. AWS also comes with many plugin services and products.
Heroku
- Platform as a Service (PAAS)
- Good documentation
- Has built-in tools and architecture.
- Limited control over architecture while designing the app.
- Deployment is taken care of (automatic via GitHub or manual via git commands or CLI).
- Not time-consuming.
AWS
- Infrastructure as a Service (IAAS)
- Versatile – has many products such as EC2, LAMBDA, EMR, etc.
- Can use a Dedicated instance for more control over the architecture, such as choosing the OS, software version, etc. There is more than one backend layer.
- Elastic Beanstalk is a feature similar to Heroku’s PAAS.
- Can use the automated deployment, or roll your own.
4. How to get the current absolute URL in Ruby on Rails?
Answer:
For Rails 3.2 or Rails 4+
You should use request.original_url
to get the current URL.
This method is documented at original_url method, but if you’re curious, the implementation is:
def original_url
base_url + original_fullpath
end
For Rails 3:
You can write "#{request.protocol}#{request.host_with_port}#{request.fullpath}"
, since request.url
is now deprecated.
For Rails 2:
You can write request.url
instead of request.request_uri
. This combines the protocol (usually http://) with the host, and request_uri to give you the full address.
Alternative Answer:
You could use url_for(only_path: false)
5. Understanding the Rails Authenticity Token
Answer:
What happens
When the user views a form to create, update, or destroy a resource, the Rails app creates a random authenticity_token
, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for the authenticity_token
, compares it to the one stored in the session, and if they match the request is allowed to continue.
Why it happens
Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself. Imagine that you are using service A, you logged into the service and everything is ok. Now imagine that you went to use service B, and you saw a picture you like and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to http://serviceA.com/close_account
. This is what is known as CSRF (Cross Site Request Forgery).
If service A is using authenticity tokens, this attack vector is no longer applicable, since the request from service B would not contain the correct authenticity token, and will not be allowed to continue.
API docs describes details about meta tag:
CSRF protection is turned on with the
protect_from_forgery
method, which checks the token and resets the session if it doesn’t match what was expected. A call to this method is generated for new Rails applications by default. The token parameter is namedauthenticity_token
by default. The name and value of this token must be added to every layout that renders forms by includingcsrf_meta_tags
in the HTML head.
Notes
Keep in mind, Rails only verifies not idempotent methods (POST, PUT/PATCH and DELETE). GET request are not checked for authenticity token. Why? because the HTTP specification states that GET requests is idempotent and should not create, alter, or destroy resources at the server, and the request should be idempotent (if you run the same command multiple times, you should get the same result every time).
Also, the real implementation is a bit more complicated as defined in the beginning, ensuring better security. Rails does not issue the same stored token with every form. Neither does it generate and store a different token every time. It generates and stores a cryptographic hash in a session and issues new cryptographic tokens, which can be matched against the stored one, every time a page is rendered. See request_forgery_protection.rb.
Lessons
Use authenticity_token
to protect your not idempotent methods (POST, PUT/PATCH, and DELETE). Also, make sure not to allow any GET requests that could potentially modify resources on the server.
Alternative Answer:
The authenticity token is designed so that you know your form is being submitted from your website. It is generated from the machine on which it runs with a unique identifier that only your machine can know, thus helping prevent cross-site request forgery attacks.
If you are simply having difficulty with rails denying your AJAX script access, you can use
<%= form_authenticity_token %>
to generate the correct token when you are creating your form.
You can read more about it in the documentation.
6. How to rollback a specific migration?
Answer:
rake db:rollback STEP=1
is a way to do this, if the migration you want to rollback is the last one applied. You can substitute 1 for however many migrations you want to go back.
For example:
rake db:rollback STEP=5
Will also rollback all the migration that happened later (4, 3, 2, and also 1).
To roll back all migrations back to (and including) a target migration, use:
rake db:migrate VERSION=20100905201547
In order to rollback ONLY ONE specific migration (OUT OF ORDER) use:
rake db:migrate:down VERSION=20100905201547
Note that this will not rollback any interceding migrations — only the one listed. If that is not what you intended, you can safely run rake db:migrate
and it will re-run only that one, skipping any others that were not previously rolled back.
And if you ever want to migrate a single migration out of order, there is also its inverse
db:migrate:up
:
rake db:migrate:up VERSION=20100905201547
Alternative Answer:
rake db:migrate:down VERSION=20100905201547
will roll back the specific file.
To find the version of all migrations, you can use this command:
rake db:migrate:status
Or, simply the prefix of the migration’s file name is the version you need to rollback.
7. How to get a random number in Ruby?
Answer:
Use rand(range)
From Ruby Random Numbers:
If you needed a random integer to simulate a roll of a six-sided die, you’d use:
1 + rand(6)
. A roll in craps could be simulated with2 + rand(6) + rand(6)
.Finally, if you just need a random float, just call
rand
with no arguments.
For instance, in this game where you need to guess 10 numbers, you can initialize them with:
10.times.map{ 20 + Random.rand(11) }
#=> [26, 26, 22, 20, 30, 26, 23, 23, 25, 22]
Note:
- Using
Random.new.rand(20..30)
(usingRandom.new
) generally would not be a good idea, as explained in detail by Marc-André Lafortune. - But if you don’t use
Random.new
, then the class methodrand
only takes amax
value, not aRange
(as documented in the docs forRandom
). Only the instance method can take aRange
, as illustrated by generate a random number with 7 digits.
This is why the equivalent of Random.new.rand(20..30)
would be 20 + Random.rand(11)
, since Random.rand(int)
returns “a random integer greater than or equal to zero and less than the argument.” 20..30
includes 30, we need to come up with a random number between 0 and 11, excluding 11.
Alternative Answer:
While you can use rand(42-10) + 10
to get a random number between 10
and 42
(where 10 is inclusive and 42 exclusive), there’s a better way since Ruby 1.9.3, where you are able to call:
rand(10...42) # => 13
Available for all versions of Ruby by requiringbackports
gem.
Ruby 1.9.2 also introduced the Random
class so you can create your own random number generator objects and has a nice API:
r = Random.new
r.rand(10...42) # => 22
r.bytes(3) # => "rnd"
The Random
class itself acts as a random generator, so you call directly:
Random.rand(10...42) # => same as rand(10...42)
Notes onRandom.new
In most cases, the simplest is to use rand
or Random.rand
. Creating a new random generator each time you want a random number is a really bad idea. If you do this, you will get the random properties of the initial seeding algorithm which are atrocious compared to the properties of the random generator itself.
If you use Random.new
, you should thus call it as rarely as possible, for example once as MyApp::Random = Random.new
and use it everywhere else.
The cases where Random.new
is helpful are the following:
- You are writing a gem and don’t want to interfere with the sequence of
rand
/Random.rand
that the main programs might be relying on. - You want separate reproducible sequences of random numbers (say one per thread).
- you want to be able to save and resume a reproducible sequence of random numbers (easy as
Random
objects can be marshalled).
8. How to use concerns in Rails 4?
Answer:
It has to do with code reuse as in the example below. Basically, the idea is to extract common and / or context specific chunks of code in order to clean up the models and avoid them getting too fat and messy.
As an example,
# app/models/concerns/taggable.rb
# notice that the file name has to match the module name
# (applying Rails conventions for autoloading)
module Taggable
extend ActiveSupport::Concern
included do
has_many :taggings, as: :taggable
has_many :tags, through: :taggings
class_attribute :tag_limit
end
def tags_string
tags.map(&:name).join(', ')
end
def tags_string=(tag_string)
tag_names = tag_string.to_s.split(', ')
tag_names.each do |tag_name|
tags.build(name: tag_name)
end
end
# methods defined here are going to extend the class, not the instance of it
module ClassMethods
def tag_limit(value)
self.tag_limit_value = value
end
end
end
So following the Product sample, you can add Taggable to any class you desire and share its functionality.
This is pretty well explained by DHH:
In Rails 4, we’re going to invite programmers to use concerns with the default app/models/concerns and app/controllers/concerns directories that are automatically part of the load path. Together with the ActiveSupport::Concern wrapper, it’s just enough support to make this light-weight factoring mechanism shine.
Alternative Answer:
1) DRYing up model codes
Consider an Article model, an Event model, and a Comment model. An article or event has many comments. A comment belongs to either Article or Event.
Traditionally, the models may look like this:
Comment Model:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Article Model:
class Article < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#return the article with least number of comments
end
end
Event Model
class Event < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#returns the event with least number of comments
end
end
As we can notice, there is a significant piece of code common to both Event and Article. Using concerns we can extract this common code in a separate module Commentable.
For this create a commentable.rb file in app/models/concerns.
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
# for the given article/event returns the first comment
def find_first_comment
comments.first(created_at DESC)
end
module ClassMethods
def least_commented
#returns the article/event which has the least number of comments
end
end
end
And now your models look like this :
Comment Model:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Article Model:
class Article < ActiveRecord::Base
include Commentable
end
Event Model:
class Event < ActiveRecord::Base
include Commentable
end
2) Skin-nizing Fat Models.
Consider an Event model. An event has many attenders and comments.
Typically, the event model might look like this
class Event < ActiveRecord::Base
has_many :comments
has_many :attenders
def find_first_comment
# for the given article/event returns the first comment
end
def find_comments_with_word(word)
# for the given event returns an array of comments which contain the given word
end
def self.least_commented
# finds the event which has the least number of comments
end
def self.most_attended
# returns the event with most number of attendes
end
def has_attendee(attendee_id)
# returns true if the event has the mentioned attendee
end
end
Models with many associations and otherwise have a tendency to accumulate more and more code and become unmanageable. Concerns provide a way to skin-nize fat modules making them more modularized and easy to understand.
The above model can be refactored using concerns as below: Create a attendable.rb
and commentable.rb
file in app/models/concerns/event folder
attendable.rb
module Attendable
extend ActiveSupport::Concern
included do
has_many :attenders
end
def has_attender(attender_id)
# returns true if the event has the mentioned attendee
end
module ClassMethods
def most_attended
# returns the event with most number of attendes
end
end
end
commentable.rb
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments
end
def find_first_comment
# for the given article/event returns the first comment
end
def find_comments_with_word(word)
# for the given event returns an array of comments which contain the given word
end
module ClassMethods
def least_commented
# finds the event which has the least number of comments
end
end
end
And now using Concerns, your Event model reduces to
class Event < ActiveRecord::Base
include Commentable
include Attendable
end
While using concerns its advisable to go for ‘domain’ based grouping rather than ‘technical’ grouping. Domain Based grouping is like ‘Commentable’, ‘Photoable’, ‘Attendable’. Technical grouping will mean ‘ValidationMethods’, ‘FinderMethods’ etc.
9. How to check if a specific key is present in a hash or not?
Answer:
Hash
‘s key?
method tells you whether a given key is present or not.
session.key?("user")
Alternative Answers:
Hash#has_key?
gets the job done, it has been deprecated in favor of Hash#key?
.hash.key?(some_key)
2) In latest Ruby versions Hash instance has a key?
method:
{a: 1}.key?(:a)
=> true
Be sure to use the symbol key or a string key depending on what you have in your hash:
{'a' => 2}.key?(:a)
=> false
10. How to “pretty” format JSON output in Ruby on Rails?
Answer:
Use the pretty_generate()
function, built into later versions of JSON. For example:
require 'json'
my_object = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_object)
Which gets you:
{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
Alternative Answer:
Thanks to Rack Middleware and Rails 3 you can output pretty JSON for every request without changing any controller of your app.
class PrettyJsonResponse
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if headers["Content-Type"] =~ /^application\/json/
obj = JSON.parse(response.body)
pretty_str = JSON.pretty_unparse(obj)
response = [pretty_str]
headers["Content-Length"] = pretty_str.bytesize.to_s
end
[status, headers, response]
end
end
The above code should be placed in app/middleware/pretty_json_response.rb
of your Rails project. And the final step is to register the middleware in config/environments/development.rb
:
config.middleware.use PrettyJsonResponse
Don’t use it inproduction.rb
. The JSON reparsing may degrade response time and throughput of your production app. Eventually, extra logic such as ‘X-Pretty-Json: true’ header may be introduced to trigger formatting for manual curl requests on demand.
(Tested with Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux)
11. Installing PostgreSQL on Ubuntu for Ruby on Rails
Answer:
Here are the steps:
Install PostgreSQL and development package
$ sudo apt-get install postgresql
$ sudo apt-get install libpq-dev
Set up a user that is the same as Ubuntu log-in
$ sudo su postgres -c psql
postgres=# CREATE ROLE <username> SUPERUSER LOGIN;
postgres=# \q
Modify Gemfile
# Remove gem 'sqlite3'
gem 'pg'
Modify database.yml
in app directory
development:
adapter: postgresql
encoding: unicode
database: appname_development
pool: 5
timeout: 5000
username: <username>
password:
test:
adapter: postgresql
encoding: unicode
database: appname_test
pool: 5
timeout: 5000
username: <username>
password:
Run bundle install
$ bundle install
Create databases and migrations
$ rake db:create:all
$ rake db:migrate
12. Difference between collection route and member route in ruby on rails?
Answer:
A member route will require an ID because it acts on a member. A collection route doesn’t because it acts on a collection of objects. Preview is an example of a member route because it acts on (and displays) a single object. Search is an example of a collection route because it acts on (and displays) a collection of objects.
In Conclusion
These are the most commonly asked questions about Ruby on Rails. If you have any suggestions regarding the article, please feel free to comment below. If you need any help, then we would be glad to help you.
We, at Truemark, provide services like web and mobile app development, digital marketing, and website development. So, if you want to work with us, please feel free to contact us.
Hope this article helped you.
1 Comment
Really enjoyed reading your blog. It is highly informative and builds great interest for the readers.
Thank you for sharing.