DEV Community

Cover image for 12 Most Asked Questions About Ruby on Rails
KiranPoudel98 for Truemark Technology

Posted on • Updated on • Originally published at thedevpost.com

12 Most Asked Questions About Ruby on Rails

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

which will create a migration file similar to:

class ChangeColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

.blank? also evaluates true on strings which are non-empty but contain only whitespace:

"  ".blank? == true
"  ".empty? == false
Enter fullscreen mode Exit fullscreen mode

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:

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

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 tohttp://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 named authenticity_token by default. The name and value of this token must be added to every layout that renders forms by including csrf_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 %>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

In order to rollback ONLY ONE specific migration (OUT OF ORDER) use:

rake db:migrate:down VERSION=20100905201547
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

will roll back the specific file.

To find the version of all migrations, you can use this command:

rake db:migrate:status
Enter fullscreen mode Exit fullscreen mode

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 with 2 + 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]
Enter fullscreen mode Exit fullscreen mode

Note:

  • Using Random.new.rand(20..30) (using Random.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 method rand only takes a max value, not a Range (as documented in the docs for Random). Only the instance method can take a Range, as illustrated by generate a random number with 7 digits.

This is why the equivalent ofRandom.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
Enter fullscreen mode Exit fullscreen mode

Available for all versions of Ruby by requiring backports 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"
Enter fullscreen mode Exit fullscreen mode

The Random class itself acts as a random generator, so you call directly:

Random.rand(10...42) # => same as rand(10...42)
Enter fullscreen mode Exit fullscreen mode

Notes on Random.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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And now your models look like this :

Comment Model:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end
Enter fullscreen mode Exit fullscreen mode

Article Model:

class Article < ActiveRecord::Base
  include Commentable
end
Enter fullscreen mode Exit fullscreen mode

Event Model:

class Event < ActiveRecord::Base
  include Commentable
end
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And now using Concerns, your Event model reduces to

class Event < ActiveRecord::Base
  include Commentable
  include Attendable
end
Enter fullscreen mode Exit fullscreen mode

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:

1) While 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
Enter fullscreen mode Exit fullscreen mode

Be sure to use the symbol key or a string key depending on what you have in your hash:

{'a' => 2}.key?(:a)
=> false
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Which gets you:

{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Don’t use it in production.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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Modify Gemfile

# Remove gem 'sqlite3'
gem 'pg'
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

Run bundle install

$ bundle install
Enter fullscreen mode Exit fullscreen mode

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.

Original Source: DevPostbyTruemark

Top comments (0)